劉博宇:Druid在滴滴應用實踐及平臺化建設

趙鈺瑩發表於2018-06-06

  本文根據劉博宇老師在2018年5月11日【第九屆中國資料庫技術大會】現場演講內容整理而成。

  講師簡介:

劉博宇:Druid在滴滴應用實踐及平臺化建設

  劉博宇,滴滴出行高階軟體開發工程師,就職於滴滴基礎平臺大資料架構部。負責Druid叢集維護與研發工作。

  摘要:

  Druid是一款支援資料實時寫入、低延時、高效能的OLAP引擎,具有優秀的資料聚合能力與實時查詢能力。在大資料分析、實時計算、監控等領域都有特定的應用場景,是大資料基礎架構建設中重要的一環。Druid在滴滴承接了包括實時報表、監控、資料分析、大盤展示等應用場景的大量業務,作為大資料基礎設施服務於公司多條業務線。本次演講我們將介紹Druid的核心特性與原理,以及在滴滴內部大規模使用中積累的經驗。

  分享大綱:

  1、Druid特性簡介

  2、Druid在滴滴的應用

  3、Druid平臺化建設

  4、展望

  正文:

  一、Druid特性簡介

  Druid是針對時間序列資料提供的低延時資料寫入以及快速互動式查詢的分散式OLAP資料庫。其兩大關鍵點是:首先,Druid主要針對時間序列資料提供低延時資料寫入和快速聚合查詢;其次,Druid是一款分散式OLAP引擎。

  針對第一個特點來看,Druid與典型的TSDB,比如InfluxDB、Graphite、OpenTSDB的部分特性類似。這些時序資料庫具備一些共同特點,一是寫入即可查,通過記憶體增量索引讓資料寫入便可查詢;二是下采樣或RDD,通過下采樣或類似於RDD的操作減少資料量,而Druid在資料寫入時就會對資料預聚合,進而減少原始資料量,節省儲存空間並提升查詢效率;三是可能會支援Schema less,在InfluxDB中,使用者可任意增加tag,InfluxDB可對新增tag進行聚合查詢,但Druid在這點上與InfluxDB略有差異,Druid需要預先定義Schema 。Druid的Schema資料打包在最後形成的資料檔案中,資料檔案按照時間分片,也就是說過去和未來資料的Schema可以不同,而不同schema的資料可以共存。所以,雖然Druid不是schema less的,但是Schema調整也是比較靈活。

  另外,Druid作為一個OLAP資料庫。OLAP資料庫需要支援類似上卷、切塊、切片、下鑽等操作,但不適合明細查詢。對於類似根據某主鍵ID定位唯一資料的任務,OLAP資料庫並不能友好支援。常用的OLAP資料庫實現方式以下幾種:1)資料檢索引擎,比如ES;2)預計算加KV儲存實現,比如Kylin;3)SQL on Hadoop 引擎,比如 Presto、SparkSQL。

  接下來,我們就以上中實現進行對比。首先是資料檢索引擎的代表ES,ES可以儲存結構化和非結構化資料,同時具備明細查詢和聚合查詢能力,由於其自身是一個資料檢索引擎,其索引型別並不是針對聚合分析設計的,所以聚合查詢方面開銷較大;其次,ES不但要儲存所有的原始資料,還需要生成較多的索引,所以儲存空間開銷會更大,資料的寫入效率方面會比Druid差一些。

  與ES相比,Druid只能處理結構化資料,因為它必須預定義Schema;其次,Druid會對資料進行預聚合以減少儲存空間,同時對資料寫入和聚合進行優化。但是,由於進行了預聚合,所以Druid拋棄掉了原始資料,導致其缺少原始明細資料查詢能力。如果業務方有需求,可以關閉預聚合,但會喪失Druid的優勢。

  其次是預計算 + kv儲存方式 ,KV儲存需要通過預計算實現聚合,可以認為Key涵蓋了查詢引數,而值就是查詢結果,由於直接從KV儲存進行查詢,所以速度非常快。缺點是因為需要在預計算中處理預設的聚合邏輯,所以損失了查詢靈活性,複雜場景下的預計算過程可能會非常耗時,而且面臨資料過於膨脹的情況;由於只有字首拼配一種索引方式,所以在大資料量的複雜過濾條件下,效能下降明顯;且缺少聚合下推能力。

  與預計算+KV儲存方式相比,Druid 是使用Bitmap索引的列式儲存,查詢速度肯定不如KV儲存快; 但是由於使用記憶體增量索引,增量預聚合的模式,寫入即可查,無需等待預計算生成Cube,所以實時性更強;其次,Druid可針對任意維度組合過濾、聚合,查詢更加靈活;最後,Scatter & Gather模式支援一定的聚合下推。

  最後是SQL on Hadoop, 這類引擎的SQL支援通常很強大,且無冗餘資料,不需要預處理。缺點是因為其直接通過計算引擎對Hadoop上的檔案進行操作,所以響應速度較慢且QPS相對較低。

  與SQL on Hadoop方式相比,Druid的SQL支援有限,但在逐漸完善;必須預定義維度指標。其優勢在於可達到亞秒級響應,併發較高。

  二、Durid在滴滴的應用

  Druid目前在滴滴使用規模大概為多個叢集百餘臺機器,日原始資料寫入量在千億級別,日落盤資料在TB級別,數百實時資料來源、千級實時寫入任務,日查詢量近千萬級。主要承接業務有監控、實時報表,大屏展示等。

  下圖為滴滴實時業務監控案例:

劉博宇:Druid在滴滴應用實踐及平臺化建設

  我們的監控體系大概可以分為三層:頂層為業務監控,主要由業務方定義指標,然後配置相應的查詢和報警。主要目的在於及時發現業務問題並告警;中層的監控體系是對各服務閘道器呼叫的監控日誌,主要為了發現某業務問題造成的影響範圍和具體影響物件;底層運維體系主要對網路、機器各方面指標進行監控。

  之所以業務監控適用Druid,是因為業務指標通常具有較為複雜多變的業務邏輯。Druid本身是一個OLAP引擎,定義一個資料來源就可衍生出眾多聚合指標,所以很適合這類靈活查詢的配置。

  第二類應用是實時報表類應用(如下圖),實時報表類應用主要用於運營資料分析,客戶端網路效能分析以及客服應答實時統計等。這些使用者通常是從Hive資料倉儲遷移過來的,因為希望獲得實時使用者體驗而Hive查詢速度太慢,所以選擇遷移。典型應用場景比如快速獲取某下雨區域的使用者單據,對使用者進行優惠券投放進而刺激使用者叫車。

劉博宇:Druid在滴滴應用實踐及平臺化建設

  第三類是大屏展示類應用(如下圖),這類應用主要用於呈現業務性關鍵結果,通常是PV、UV或TOP N查詢,非常適合Druid。

劉博宇:Druid在滴滴應用實踐及平臺化建設

  三、Druid平臺化建設

  在承接應用場景的過程中,我們做了很多平臺化建設。簡單啊介紹下平臺化建設的背景: 業務資料主要來源是日誌和binlog;公司統一資料通道是kafka;業務指標多樣,邏輯複雜多變;Druid接入配置較複雜,除Schema配置外,還包括實時任務配置;資料進入Druid之前通常需要流計算處理,業務方自己開發既費時又很容易出現問題;Druid資料的對應關係以及資料來源衍生指標鏈路較長,需要進行上下游關係梳理;由於Druid官方主要通過API查詢,未提供資料視覺化服務元件,因此業務方急需資料視覺化相關服務元件。

  在以上的背景下,我們構建了實時計算平臺,架構圖如下:

劉博宇:Druid在滴滴應用實踐及平臺化建設

  底層引擎有三部分組成,流計算引擎包括Flink Streaming和Spark Streaming,儲存部分主要依靠Druid;流計算引擎之上,我們主要開發了WebIDE和任務管理功能,WebIDE在Web內部整合,我們會為使用者提供相應模板,使用者根據相應的模板進行進行開發,即可形成自己的流計算任務,簡化了一些邏輯較簡單的常見ETL、Join任務的開發。任務完成後可通過任務管理平臺直接提交,同時使用者自己在本地開發的流計算任務也可以上傳到平臺,通過平臺執行,平臺對任務提供相應的指標檢測。基於Druid引擎,配置 Druid資料來源,通過資料來源衍生指標,每一個指標其實就是對Druid的一個查詢。使用者可針對指標配置告警。上圖右側的DCube是一個拖拽式資料分析的前端工具,DSQL讓使用者可直接寫SQL的方式輸出Druid的即席查詢能力。

  根據配置的指標進行告警,分為兩大類,一類是閾值告警;一類是模型告警。通常對規律性不太強的數值配置閾值告警,對規律性較強的指標配置模型告警。如滴滴每天的訂單呼叫量基本上呈現一個早高峰、一個晚高峰,中間較平穩的狀態。通常會選取過去一段時間的資料進行模型訓練,由使用者在得到的預測基線上設定置信區間。如果資料超過置信區間,就會報警。當然,也會存在一些較難處理的特殊情況,比如突然下雨、熱門電影首映結束等導致的訂單激增,需要額外去考慮一些情況。

劉博宇:Druid在滴滴應用實踐及平臺化建設

  上圖為基本工作流,整體工作流程為由MySQL的binlog和日誌採集資料,形成原始topic,經過ETL或者多流Join進入清洗後的topic,此時使用者可以使用平臺提供的魔板功能或自行開發流計算任務,我們會為所有流計算任務定製一些預設的實時指標,這些指標和使用者的業務資料都會在Druid中建立datasource。Druid也可通過Hive離線匯入資料,離線資料來源和實時資料來源兩部分組成了Druid的基本資料,之後根據基本資料構建業務指標、任務指標,完成報警配置。如果業務方具備一定開發能力,需要把資料接入到自己的系統,我們也會提供一些Open API。平臺為使用者提供了自助式的Druid資料來源接入頁面,極大簡化地了Druid資料接入的複雜過程。

  Druid查詢採用100% SQL 的Web化配置。Druid原生查詢是DSL,類似JSON格式,但學習成本較高。在支援SQL之後,除了部分使用者自建服務外,平臺所有查詢全部遷移到SQL。

  在平臺化過程中,我們遇到了一些挑戰:一是核心業務與非核心業務共享資源,存在一定風險;二是使用者自助提交任務配置、查詢不合理,造成異常情況,甚至影響整個叢集的穩定性;三是隨著業務的快速發展,Druid依賴的元件都需要熱遷移到獨立部署環境。在滴滴內部,由於Druid資料來源基本都是使用者自助接入,所以業務增長迅速,一年時間幾乎漲了四倍,這對Druid依賴元件的熱遷移提出了要求。

  針對不同重要程度的業務共享資源問題,首先建設 Druid叢集的異地雙活機制,核心資料來源的叢集級雙活。其次,通過統一閘道器對使用者遮蔽多叢集細節,同時根據使用者身份進行查詢路由,實現查詢資源隔離。最後,進行業務分級,核心業務進行叢集級雙活,對查詢資源需求較大但不過分要求實時性的業務分配獨立的查詢資源組,其他使用者使用預設資源池。

劉博宇:Druid在滴滴應用實踐及平臺化建設

  上圖為基本架構圖,首先我們會有多個查詢節點分佈在不同叢集,非核心資料來源單寫到公共叢集,核心資料來源雙寫到兩個叢集,使用者使用身份驗證key通過閘道器路由進行查詢。

  針對使用者配置與查詢不合理造成的異常,我們主要做了以下三點:一是引擎層面進行bad case防範,例如,druid資料時間欄位設定合理的時間視窗限制,如果資料時間範圍異常,我們就會對它進行拋棄;二是對Druid原生API進行封裝,提供更加合理的預設配置,主要針對實時任務時長、任務數量以及記憶體進行配置;三是完善指標監控體系與異常定位手段,保證捕捉到異常查詢。Druid和閘道器日誌通常會通過流計算任務進行處理,然後把它們分別寫入Druid和ES,數值指標會上報到Graphite,通過Grafana進行展示,綜合利用 Druid的聚合分析能力與和ES的明細查詢能力定位異常。

  針對依賴元件的熱遷移問題,Druid主要依賴的元件有三個:ZooKeeper、MySQL、HDFS。在過去一年,滴滴完成了三大元件的遷移,主要過程如下:

  1、ZooKeeper遷移原理:擴容-叢集分裂-縮容

劉博宇:Druid在滴滴應用實踐及平臺化建設

  在滴滴內部,ZK原來是與其他業務共用的,我們需要保證其他業務和Druid都不停服的情況下,把Druid的ZK叢集單獨遷移出來,所以我們採用了上述遷移方案。核心思路就是先擴容,隨後利用兩套叢集配置,觸發叢集分裂,最後縮容掉不需要的節點。如圖4所示,這七臺ZK配置其實有兩套,第一套是12347五臺,第二套是567三臺,但它們的leader都是ZK7,此時7個節點同屬一個叢集。當重啟ZK7之後,兩套配置的ZK節點會分別獨立選取leader,此時進行叢集分裂變成兩個單獨的ZK叢集。

  2、MySQL熱遷移實踐

劉博宇:Druid在滴滴應用實踐及平臺化建設

  我們主要使用Kafka-indexing-service作為實時資料寫入方式。在實時任務執行過程中,會後設資料不斷更新到MySQL中的。要想對Mysql進行遷移,首先需要保證後設資料在遷移過程中不變,因此首先要了解該資料寫入流程。在Kafka-indexing-service的實時任務執行過程中,後設資料更新主要來自於實時任務執行狀態的變化和資料消費相關的部分API呼叫。實時任務的生命週期包括讀取資料和釋出資料兩個過程,讀取資料是從kafka讀取,在記憶體中建立增量索引;釋出資料過程,就是把實時節點消費的資料下推到歷史節點,其實是通過首先寫到HDFS,然後再由歷史節點載入。只有在實時任務狀態發生改變時,才會產生後設資料更新操作。因此,我們開發了實時任務狀態凍結API,把所有實時任務的生命週期都凍結在資料reading的狀態,此時進行MySQL遷移,遷移完成之後,重新啟動Overlord(一個管理實時任務的節點,所有實時任務的資料狀態變化都由Overlord觸發),實時任務就會繼續進行生命週期迭代。

  3、HDFS遷移實踐

劉博宇:Druid在滴滴應用實踐及平臺化建設

  剛才提到了HDFS在資料釋出流程中的作用,資料釋出就是指實時節點消費到的資料下推到歷史節點的過程。下推的方式就是先推到HDFS,再由歷史節點從HDFS拉取。Master節點會告訴歷史節點那些資料是需要其拉取的,而從哪裡拉取則是從後設資料儲存中獲得的,我們需要做的是保證歷史節點可以從兩個HDFS讀取資料,同時滾動重啟實時節點,保證增量資料寫到新的HDFS,歷史節點從新的HDFS拉取資料。對於存量資料我們只需要更改後設資料裡歷史資料的路徑,就可以無縫替換原有HDFS。

  接下來簡單介紹Druid平臺化建設效能優化部分的工作。首先簡單介紹下Druid的三種資料寫入方式:

  1、Standalone Realtime Node

  該模式屬於單機資料消費,失敗後無法恢復,且由於其內部實現機制,該模式無法實現HA,這種方式官方也不推薦使用。

  2、Tranquility + indexing-service

  該方式主要通過Tranquility 程式消費資料,把資料主動push給indexing- service服務,優勢是Tranquility 程式可以幫助管理資料副本、資料實時任務以及生命週期等;其缺點是如果所有副本全部任務失敗,無法恢復資料;必須設定資料遲到容忍視窗,該視窗與任務時長掛鉤,由於任務時長有限,因此很難容忍長時間資料遲到。

  3、Kafka-indexing-service

  這是Druid比較新的寫入方式,其優勢主要體現在資料可靠性及任務恢復方面,彌補了前兩種方式的不足。其缺點是資料消費過於依賴Overlord服務,Overlord單機效能將會成為叢集規模瓶頸 ;由於Segment與Kafka topic的partition關聯,因此容易造成後設資料過度膨脹,進而引發效能問題。最終,我們選擇Kafka-indexing-service 模式,並開始解決該模式存在的問題。

  該寫入方式面臨的問題經過定位主要有以下三個:一是MySQL查詢效能問題, Overlord提供的多個API需要直接對MySQL進行操作,所以MySQL查詢效能直接影響Overlord併發水平;二是Druid裡所有資料都是JSON儲存格式,反序列化非常耗時;三是 Druid中實時任務狀態都通過ZK釋出,Overlord會監聽ZK上面的節點,而這些監聽器的回撥執行緒執行函式中會涉及一些MySQL操作,當MySQL比較繁忙時, ZK watch回撥單執行緒模型導致事件處理需要排隊。

  針對查詢效能瓶頸,我們主要針對Druid後設資料儲存索引進行了優化。通過對Segment定時Merge,合理設定資料生命週期來合併精簡後設資料; 對Druid資料庫連線池DBCP2引數進行優化。針對反序列化與watch回撥問題,我們主要對Druid任務管理體系進行了較大修改,進行了Overlord Federation改造,引入namespace概念,每一個namespace下的任務又單獨的Overlord管理。這樣增加Overlord水平擴充套件能力,同時亦可做Overlord級別的資源隔離。

  四、展望

  目前Druid資料消費能力依賴Kafka topic的partition,未來我們希望引入流計算引擎提升單partition消費能力,解耦對Kafka topic partition的依賴,對資料消費和資料處理進行不同的併發度配置。其次,Overlord大量服務涉及對MySQL的直接操作,易導致單機效能瓶頸,後續將會對高併發服務進行記憶體化改造。資料下推到HDFS之後,Coordinator(Druid裡資料分配角色)決定資料的載入位置,這是一個單執行緒執行模型,當Overload水平擴充套件之後,每個時間點產生的Segment數量會有很大提升,Coordinator任務處理單執行緒模型需要優化。最後, 我們希望把Druid部分元件On-yarn,進而提升資源利用率並簡化運維操作。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31077337/viewspace-2155685/,如需轉載,請註明出處,否則將追究法律責任。

相關文章