Druid在有贊的實踐

一、Druid介紹

Druid 是 MetaMarket 公司研發,專為海量數據集上的做高性能 OLAP (OnLine Analysis Processing)而設計的數據存儲和分析系統,目前Druid 已經在Apache基金會下孵化。Druid的主要特性:

  • 交互式查詢( Interactive Query ): Druid 的低延遲數據攝取架構允許事件在它們創建后毫秒內查詢,因為 Druid 的查詢延時通過只讀取和掃描有必要的元素被優化。Druid 是列式存儲,查詢時讀取必要的數據,查詢的響應是亞秒級響應。
  • 高可用性( High Available ):Druid 使用 HDFS/S3 作為 Deep Storage,Segment 會在2個 Historical 節點上進行加載;攝取數據時也可以多副本攝取,保證數據可用性和容錯性。
  • 可伸縮( Horizontal Scalable ):Druid 部署架構都可以水平擴展,增加大量服務器來加快數據攝取,以及保證亞秒級的查詢服務
  • 并行處理( Parallel Processing ): Druid 可以在整個集群中并行處理查詢
  • 豐富的查詢能力( Rich Query ):Druid支持 Scan、 TopN、 GroupBy、 Approximate 等查詢,同時提供了2種查詢方式:API 和 SQL

Druid常見應用的領域:

  • 網頁點擊流分析
  • 網絡流量分析
  • 監控系統、APM
  • 數據運營和營銷
  • BI分析/OLAP

二、為什么我們需要用 Druid

有贊作為一家 SaaS 公司,有很多的業務的場景和非常大量的實時數據和離線數據。在沒有是使用 Druid 之前,一些 OLAP 場景的場景分析,開發的同學都是使用 SparkStreaming 或者 Storm 做的。用這類方案會除了需要寫實時任務之外,還需要為了查詢精心設計存儲。帶來問題是:開發的周期長;初期的存儲設計很難滿足需求的迭代發展;不可擴展。
在使用 Druid 之后,開發人員只需要填寫一個數據攝取的配置,指定維度和指標,就可以完成數據的攝入;從上面描述的 Druid 特性中我們知道,Druid 支持 SQL,應用 APP 可以像使用普通 JDBC 一樣來查詢數據。通過有贊自研OLAP平臺的幫助,數據的攝取配置變得更加簡單方便,一個實時任務創建僅僅需要10來分鐘,大大的提高了開發效率。

2.1、Druid 在有贊使用場景

  • 系統監控和APM:有贊的監控系統(天網)和大量的APM系統都使用了 Druid 做數據分析
  • 數據產品和BI分析:有贊 SaaS 服務為商家提供了有很多數據產品,例如:商家營銷工具,各類 BI 報表
  • 實時OLAP服務:Druid 為風控、數據產品等C端業務提供了實時 OLAP 服務

三、Druid的架構

image

Druid 的架構是 Lambda 架構,分成實時層( Overlord、 MiddleManager )和批處理層( Broker 和 Historical )。主要的節點包括(PS: Druid 的所有功能都在同一個軟件包中,通過不同的命令啟動):

  • Coordinator 節點:負責集群 Segment 的管理和發布,并確保 Segment 在 Historical 集群中的負載均衡
  • Overlord 節點:Overlord 負責接受任務、協調任務的分配、創建任務鎖以及收集、返回任務運行狀態給客戶端;在Coordinator 節點配置 asOverlord,讓 Coordinator 具備 Overlord 功能,這樣減少了一個組件的部署和運維
  • MiddleManager 節點:負責接收 Overlord 分配的索引任務,創建新啟動Peon實例來執行索引任務,一個MiddleManager可以運行多個 Peon 實例
  • Broker 節點:負責從客戶端接收查詢請求,并將查詢請求轉發給 Historical 節點和 MiddleManager 節點。Broker 節點需要感知 Segment 信息在集群上的分布
  • Historical 節點:負責按照規則加載非實時窗口的Segment
  • Router 節點:可選節點,在 Broker 集群之上的API網關,有了 Router 節點 Broker 不在是單點服務了,提高了并發查詢的能力

四、有贊 OLAP 平臺的架構和功能解析

4.1 有贊 OLAP 平臺的主要目標:

  • 最大程度的降低實時任務開發成本:從開發實時任務需要寫實時任務、設計存儲,到只需填寫配置即可完成實時任務的創建
  • 提供數據補償服務,保證數據的安全:解決因為實時窗口關閉,遲到數據的丟失問題
  • 提供穩定可靠的監控服務:OLAP 平臺為每一個 DataSource 提供了從數據攝入、Segment 落盤,到數據查詢的全方位的監控服務

4.2 有贊 OLAP 平臺架構

image

有贊 OLAP 平臺是用來管理 Druid 和周圍組件管理系統,OLAP平臺主要的功能:

  • Datasource 管理
  • Tranquility 配置和實例管理:OLAP 平臺可以通過配置管理各個機器上 Tranquility 實例,擴容和縮容
  • 數據補償管理:為了解決數據遲延的問題,OLAP 平臺可以手動觸發和自動觸發補償任務
  • Druid SQL查詢: 為了幫助開發的同學調試 SQL,OLAP 平臺集成了 SQL 查詢功能
  • 監控報警

4.2 Tranquility 實例管理

OLAP 平臺采用的數據攝取方式是 Tranquility工具,根據流量大小對每個 DataSource 分配不同 Tranquility 實例數量; DataSource 的配置會被推送到 Agent-Master 上,Agent-Master 會收集每臺服務器的資源使用情況,選擇資源豐富的機器啟動 Tranquility 實例,目前只要考慮服務器的內存資源。同時 OLAP 平臺還支持 Tranquility 實例的啟停,擴容和縮容等功能。

image

4.3 解決數據遲延問題——離線數據補償功能

流式數據處理框架都會有時間窗口,遲于窗口期到達的數據會被丟棄。如何保證遲到的數據能被構建到 Segment 中,又避免實時任務窗口長期不能關閉。我們研發了 Druid 數據補償功能,通過 OLAP 平臺配置流式 ETL 將原始的數據存儲在 HDFS 上,基于 Flume 的流式 ETL 可以保證按照 Event 的時間,同一小時的數據都在同一個文件路徑下。再通過 OLAP 平臺手動或者自動觸發 Hadoop-Batch 任務,從離線構建 Segment。

image

基于 Flume 的 ETL 采用了 HDFS Sink 同步數據,實現了 Timestamp 的 Interceptor,按照 Event 的時間戳字段來創建文件(每小時創建一個文件夾),延遲的數據能正確歸檔到相應小時的文件中。

4.4 冷熱數據分離

隨著接入的業務增加和長期的運行時間,數據規模也越來越大。Historical 節點加載了大量 Segment 數據,觀察發現大部分查詢都集中在最近幾天,換句話說最近幾天的熱數據很容易被查詢到,因此數據冷熱分離對提高查詢效率很重要。Druid 提供了Historical 的 Tier 分組機制與數據加載 Rule 機制,通過配置能很好的將數據進行冷熱分離。
首先將 Historical 群進行分組,默認的分組是"_default_tier",規劃少量的 Historical 節點,使用 SATA 盤;把大量的 Historical 節點規劃到 "hot" 分組,使用 SSD 盤。然后為每個 DataSource 配置加載 Rule :

  • rule1: 加載1份最近30天的 Segment 到 "hot" 分組;
  • rule2: 加載2份最近6個月的 Segment 到 "_default_tier" 分組;
  • rule3: Drop 掉之前的所有 Segment(注:Drop 只影響 Historical 加載 Segment,Drop 掉的 Segment 在 HDFS 上仍有備份)
{"type":"loadByPeriod","tieredReplicants":{"hot":1}, "period":"P30D"} 
{"type":"loadByPeriod","tieredReplicants":{"_default_tier":2}, "period":"P6M"} 
{"type":"dropForever"}

提高 "hot"分組集群的 druid.server.priority 值(默認是0),熱數據的查詢都會落到 "hot" 分組。

image

4.5 監控與報警

Druid 架構中的各個組件都有很好的容錯性,單點故障時集群依然能對外提供服務:Coordinator 和 Overlord 有 HA 保障;Segment 是多副本存儲在HDFS/S3上;同時 Historical 加載的 Segment 和 Peon 節點攝取的實時部分數據可以設置多副本提供服務。同時為了能在節點/集群進入不良狀態或者達到容量極限時,盡快的發出報警信息。和其他的大數據框架一樣,我們也對 Druid 做了詳細的監控和報警項,分成了2個級別:

  • 基礎監控
    包括各個組件的服務監控、集群水位和狀態監控、機器信息監控
  • 業務監控
    業務監控包括:實時任務創建、數據攝取 TPS、消費遲延、持久化相關、查詢 RT/QPS 等的關鍵指標,有單個 DataSource 和全局的2種不同視圖;同時這些監控項都有設置報警項,超過閾值觸發報警提醒。業務指標的采集是大部分是通過 Druid 框架自身提供的 Metrics 和 Alerts 信息,然后流入到 Kafka / OpenTSDB 等組件,通過流數據分析獲得我們想要的指標。

4.6 部署架構

image

Historical 集群的部署和4.4節中描述的數據冷熱分離相對應,用 SSD 集群存儲最近的N天的熱數據(可調節 Load 的天數),用相對廉價的 Sata 機型存儲更長時間的歷史冷數據,同時充分利用 Sata 的 IO 能力,把 Segment Load到不同磁盤上;在有贊有很多的收費業務,我們在硬件層面做隔離,保證這些業務在查詢端有足夠的資源;在接入層,使用 Router 做路由,避免了 Broker 單點問題,也能很大的程度集群查詢吞吐量;在 MiddleManager 集群,除了部署有 Index 任務(內存型任務)外,我們還混合部署了部分流量高 Tranquility 任務(CPU型任務),提高了 MiddleManager 集群的資源利用率。

4.7 貢獻開源社區

在有贊業務查詢方式一般是 SQL On Broker/Router,我們發現一旦有少量慢查詢的情況,客戶端會出現查詢不響應的情況,而且連接越來越難獲取到。登錄到Broker 的服務端后發現,可用連接數量急劇減少至被耗盡,同時出現了大量的 TCP Close_Wait。用 jstack 工具排查之后發現有 deadlock 的情況,具體的 Stack 請查看 ISSUE-6867

經過源碼排查之后發現,DruidConnection為每個 Statement 注冊了回調。在正常的情況下 Statement 結束之后,執行回調函數從 DruidConnection 的 statements 中 remove 掉自己的狀態;如果有慢查詢的情況(超過最長連接時間或者來自客戶端的Kill),connection 會被強制關閉,同時關閉其下的所有 statements ,2個線程(關閉connection的線程和正在退出 statement 的線程)各自擁有一把鎖,等待對方釋放鎖,就會產生死鎖現象,連接就會被馬上耗盡。

// statement線程退出時執行的回調函數
final DruidStatement statement = new DruidStatement(
    connectionId,
    statementId,
    ImmutableSortedMap.copyOf(sanitizedContext),
    () -> {
        // onClose function for the statement
        synchronized (statements) {
           log.debug("Connection[%s] closed statement[%s].", connectionId, statementId);
           statements.remove(statementId);
       }
    }
);
// 超過最長連接時間的自動kill
return connection.sync(
    exec.schedule(
        () -> {
          log.debug("Connection[%s] timed out.", connectionId);
          closeConnection(new ConnectionHandle(connectionId));
        },
        new Interval(DateTimes.nowUtc(), config.getConnectionIdleTimeout()).toDurationMillis(),
        TimeUnit.MILLISECONDS
    )
);

在排查清楚問題之后,我們也向社區提了 PR-6868 。目前已經成功合并到 Master 分支中,將會 0.14.0 版本中發布。如果讀者們也遇到這個問題,可以直接把該PR cherry-pick 到自己的分支中進行修復。

五、挑戰和未來的展望

5.1 數據攝取系統

目前比較常用的數據攝取方案是:KafkaIndex 和 Tranquility 。我們采用的是 Tranquility 的方案,目前 Tranquility 支持了 Kafka 和 Http 方式攝取數據,攝取方式并不豐富;Tranquility 也是 MetaMarket 公司開源的項目,更新速度比較緩慢,不少功能缺失,最關鍵的是監控功能缺失,我們不能監控到實例的運行狀態,攝取速率、積壓、丟失等信息。
目前我們對 Tranquility 的實例管理支持啟停,擴容縮容等操作,實現的方式和 Druid 的 MiddleManager 管理 Peon 節點是一樣的。把 Tranquility 或者自研攝取工具轉換成 Yarn 應用或者 Docker 應用,就能把資源調度和實例管理交給更可靠的調度器來做。

5.2 Druid 的維表 JOIN 查詢

Druid 目前并不沒有支持 JOIN查詢,所有的聚合查詢都被限制在單 DataSource 內進行。但是實際的使用場景中,我們經常需要幾個 DataSource 做 JOIN 查詢才能得到所需的結果。這是我們面臨的難題,也是 Druid 開發團隊遇到的難題。

5.3 整點查詢RT毛刺問題

對于 C 端的 OLAP 查詢場景,RT 要求比較高。由于 Druid 會在整點創建當前小時的 Index 任務,如果查詢正好落到新建的 Index 任務上,查詢的毛刺很大,如下圖所示:

image

我們已經進行了一些優化和調整,首先調整 warmingPeriod 參數,整點前啟動 Druid 的 Index 任務;對于一些 TPS 低,但是 QPS 很高的 DataSource ,調大 SegmentGranularity,大部分 Query 都是查詢最近24小時的數據,保證查詢的數據都在內存中,減少新建 Index 任務的,查詢毛刺有了很大的改善。盡管如此,離我們想要的目標還是一定的差距,接下去我們去優化一下源碼。

5.4 歷史數據自動Rull-Up

現在大部分 DataSource 的 Segment 粒度( SegmentGranularity )都是小時級的,存儲在 HDFS 上就是每小時一個Segment。當需要查詢時間跨度比較大的時候,會導致Query很慢,占用大量的 Historical 資源,甚至出現 Broker OOM 的情況。如果創建一個 Hadoop-Batch 任務,把一周前(舉例)的數據按照天粒度 Rull-Up 并且 重新構建 Index,應該會在壓縮存儲和提升查詢性能方面有很好的效果。關于歷史數據 Rull-Up 我們已經處于實踐階段了,之后會專門博文來介紹。

最后打個小廣告,有贊大數據團隊基礎設施團隊,主要負責有贊的數據平臺 (DP), 實時計算 (Storm, Spark Streaming, Flink),離線計算 (HDFS, YARN, HIVE, SPARK SQL),在線存儲(HBase),實時 OLAP (Druid) 等數個技術產品,歡迎感興趣的小伙伴聯系 zhaojiandong@youzan.com

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Druid基本概念及架構介紹 1.什么是Druid Druid是一個專為大型數據集上的高性能切片和OLAP分析而設...
    it_zzy閱讀 53,330評論 0 32
  • Druid.io(以下簡稱Druid)是面向海量數據的、用于實時查詢與分析的OLAP存儲系統。Druid的四大關鍵...
    大詩兄_zl閱讀 6,482評論 0 9
  • 概覽 事件流的分析 druid 提供了快速的分析查詢一個高并發,在實時節點和歷史節點上;強大的用戶交互界面; 重構...
    93張先生閱讀 4,152評論 1 1
  • #refer1:http://www.cnblogs.com/xd502djj/p/6408979.html#re...
    liuzx32閱讀 1,929評論 0 1
  • 我們知道Druid能夠同時提供對大數據集的實時攝入和高效復雜查詢的性能,主要原因就是它獨到的架構設計和基于Data...
    零度沸騰_yjz閱讀 21,553評論 3 17