druid.io剖析

druid.io剖析

簡介

druid做爲如今最有潛力的海量數據實時分析系統,在優酷廣告團隊中扮演者很是重要的角色node

總體架構

總體架構

如今已經用tranquility+indexing service替換realtimemysql

實時數據經由tranquility被推送到Indexing Service,而後生成索引(Segment),同時提供來自用戶的 查詢請求。當索引所在的時間段過去之後,Indexing Service會將索引推送到deep storage。 索引信息會被註冊到metadata中。協調節點定時同步metadata,感知新生成的Segment, 並經過Zookeeper去通知歷史節點加載索引。git

除了實時加載數據,Druid也支持批量導入數據。導入的數據生成索引segment,寫入deep storage, 經與上述一樣的步驟,經過修改metadata信息將segment加載到歷史節點。github

Lambda架構思想

Lamda架構用來同時處理離線和實時數據算法

lambda架構

druid藉助lambda思想,很好的解決了實時處理邏輯會丟棄時間窗口之外的數據的問題。sql

  • 實時:經過tranquility拉取數據並導入druid
  • 離線:經過druid提供的Hadoop Indexer(其實是mr任務)獲取hdfs數據,生成segment並導入hdfs,並將索引元信息導入mysql。druid定時輪詢mysql並獲取最新索引數據,最後經過指定負載均衡算法分配給工做節點

依賴

kafka(16c32g480gx8)

TT日誌-->storm etl-->kafkajson

kafka做爲storm和druid之間的緩衝緩存

tranquility(4c8g120gx9)

/home/admin/druid-tranquility/default架構

config目錄存儲了不少json文件,定義了數據源的schema,也就是druid表結構,全部schema中配置的segmentGranularity都是hour級別, queryGranularity有hour也有minute級別併發

重要參數

segmentGranularity不等於queryGranularity

  • segmentGranularity:索引粒度,也就是一個segment文件包含的數據時間範圍
  • queryGranularity:查詢粒度,也就是最小聚合粒度,表明數據存儲的時候,在維度相同的狀況下,同一查詢粒度範圍內的數據會自動被聚合,致使查詢的時候只能查到該粒度級別的數據
  • intermediatePersistPeriod:定時持久化增量索引的週期,目前大可能是5min
  • windowPeriod:時間窗口,表示若是數據時間比當前時間老或者比當前時間新,超過該窗口範圍以外的所有被丟棄,目前大可能是10min,也有5min

推薦配置:intermediatePersistPeriod ≤ windowPeriod < segmentGranularity,queryGranularity<= segmentGranularity

tranquility工做流程:

tranquility

簡而言之,tranquility會作兩件事:

  • 創建索引任務併發給overlord:tranquility發送的task會被overlord接受,最後會佔用middle-manager的一個空閒slot。爲防止太多task,tranquility會爲同一個segmentGranularity範圍以內的task分配同一個id,這個全部發送過去的task都會被合併。還有兩個配置項影響task數量,tranquility能夠在schema中爲每一個數據源配置partitions和replicants,一個小時之內請求的task數量= partitions * replicants。目前middle-manager的全部slot數量均可以在overlord UI查看,能夠根據剩餘slot數量來修改配置中的partitions和replicants參數。創建的task主要目的是明確每一個tranquility該往哪一個peon發送實時數據,即實時數據在衆多peon中負載均衡的策略(稍後討論handoff階段
  • 將實時數據發送給peon進程:peon會經過EventReceiverFirehose服務暴露一個http接口,tranquility經過zookeeper獲取task的分配信息,明確實時數據該往哪一個peon發,並將peon暴露的接口發起post請求,提交實時數據

內部組件

indexing service

indexing service分爲三個組件(工做進程),用相似storm的nimbus->supervisor->worker的方式工做

  • overlord(4c8g120gx2):接收tranquility請求的實時索引task,選擇slot空閒最多的middle-manager,經過zk將task分配給middle-manager,填滿爲止。目前overlord兩臺機器,master-slave結構
  • middle-manager(4c8g120gx51):經過zk獲取task,啓動本地進程peon執行task
  • peon:獲取實時數據,執行task,完成索引創建。peon自己還負責索引查詢服務

index service接收tranquility請求並處理的整個流程:

indexing service

peon完成了索引build,merge,handoff的整個生命週期

peon-flow

每一個middle-manger有N個slot,對應N個peon,每次分配一個索引task就會建立一個peon進程,這個小時之內peon會佔據這個slot,等完成handoff以後才釋放

這個小時之內,peon會不斷生成增量索引,定時持久化索引,合併索引生成segment,最後handoff segment

handoff流程:

handoff

historical(16c32g480gx10)

historical提供索引加載和查詢服務

historical

歷史節點在從下載segment前,會從本地緩存檢查是否存在,若是不存在才從hdfs下載。下載完成以後,會根據zk獲取到的壓縮信息進行解壓處理並加載到內存,這時就能提供查詢服務。

能夠經過配置給歷史節點劃分不一樣的層,而後在coordinator配置規則來加載指定數據源到某個層。這樣能夠實現冷熱數據劃分處理,熱數據查詢多存量小,採用更好的cpu和內存機型配置,冷數據查詢少存量大,採用更大的硬盤機型配置

broker(16c32g480gx2)

broker負責查詢索引,目前是master-master結構

broker是查詢節點,負責接受查詢請求,解析查詢對象中的時間範圍,根據時間範圍將實時索引請求(當前小時)路由到peon節點,將歷史索引請求(1小時以前)路由到historical節點。接收peon和historical查詢返回的數據,在作一次合併,最後返回結果

爲了提升查詢效率,broker會將查詢結果緩存(LRU),目前提供了兩種方式:

  • heap memory(目前使用)
  • kv存儲,如memcached

只會緩存歷史節點返回的數據,由於peon返回的實時數據常常改變,沒有緩存的價值

coordinator(4c8g120gx2)

coordinator會協調歷史節點中segment的分配

  • rules:每分鐘從mysql拉取druid_rules和druid_segments,rules用來告知historical將如何load和drop索引文件,coordinator會讀取這些rules,而後修改zk,通知historical加載刪除指定的segment,這些均可以在coordinator的UI配置
  • load balance:根據zk中每一個historical node負責的segment量,作負載均衡
  • replication:在coordinator的UI中配置rules時,能夠同時配置加載segment的備份數量,這些備份數量會以load balance的形式,分配到多個historical上面。這個備份數量與hdfs的segment備份數量不同,hdfs那個保證深度存儲的數據不會丟失,historical上面備份是爲了保證當某個historical掛掉的時候,其餘存儲了備份segment的節點能接着提供查詢服務

外部依賴

zookeeper

druid依賴zk實現集羣之間的交互

druid採用shard-nothing架構,每一個節點之間不直接和其餘打交道,而是採用zk來溝通。這樣保證了druid自己的HA特性

peon和historical發佈索引

  • /druid/announcements:聲明全部peon和historical的host
  • /druid/segments:記錄全部peon和historical的host,以及他們負責的索引

提供indexing service相關數據(overlord頁面數據來源)

  • /druid/indexer
  • leaderLatchPath:overlord選主
  • tasks:運行的peon任務
  • status:peon任務狀態
  • announcements:聲明middle-manager的capacity

coordinator用來通知historical加載卸載索引

  • /druid/loadQueue/_historical_host/_segement_id:記錄歷史節點所負責的segment

coordinator選主

  • coordinator:記錄coordinator信息

集羣通訊

  • discovery:集羣中全部服務

附屬功能

  • /druid/listeners:存儲lookup數據

deep storage —— hdfs

存儲索引文件

metadata storage —— mysql

存儲元數據

  • druid_segments:索引元數據,數據源、是否可用、大小、維度、指標
  • druid_rules:通知historical該如何加載、卸載索引的規則,能夠在coordinator配置
  • druid_config:存放運行時配置信息
  • druid_audit:記錄配置、規則的變化
  • druid_task(相關的幾張表):overlord用來存放索引task數據,防止overlord掛掉致使task丟失

索引文件

segment就是壓縮後的索引文件,命名方式爲datasource_intervalStart_intervalEnd_version_partitionNum。如dsp_report_2011-01-01T01:00:00Z_2011-01-01T02:00:00Z_v1_0,表明dsp_report數據源,從2011-01-01那天1點到2點的數據,版本號爲v1,分區數爲0

深刻剖析segment存儲結構

  • version.bin:4字節,記錄segment version
  • XXXXX.smoosh:該文件存放多個邏輯意義上的子文件,經過記錄offset來管理這些子文件。有的子文件存放了column信息,有的存放了索引元信息。column信息也就是真實存儲的數據
  • meta.smoosh:上面這些子文件名稱以及他們出現的offset都記錄在meta.smoosh中

XXXXX.smoosh中存放的column是最重要的,能夠分爲Timestamp, Dimensions, Metrics三部分。

timestamp domain advertiser device city click cost
2015-11-25T10:00:00Z youku.com BMW Android Peking 9 0.9
2015-11-25T10:00:00Z youku.com BMW Iphone HongKong 3 0.3
2015-11-25T10:00:00Z tudou.com PANDORA Iphone HongKong 2 0.2
2015-11-25T10:00:00Z tudou.com PANDORA Iphone Peking 1 0.1
  • Timestamp:用時間戳來表示時間,能夠用一系列時間戳表示該segment全部Timestamp列信息,採用LZ4算法壓縮
  • Metrics:也是數字,存放方法同上,壓縮算法同上
  • Dimensions:因爲Dimensions大可能是字符串,採用上面的存放方式沒法很好壓縮。目前Dimensions拆分紅多個結構進行存儲。

Dimensions結構:

  1. 將字符串映射爲整數id的字典
  2. 記錄該dimension每一行的值,值用上述字典編碼
  3. 爲每一個不一樣dimension的值,定義一個bitmap,存儲該值出現的行號,採用roaring壓縮算法

上述結構中,1能夠有效減小索引文件的大小,2的基礎上作排序能夠很方便的作groupby合併處理,3是快速完成where條件查詢的利器。

內存管理

druid使用了三種不一樣類型的內存:

  • 堆內存:broker用來緩存查詢結果、簡單計算
  • 直接內存:通常用來存儲聚合操做中所產生的臨時數據
  • MMap:歷史節點用來加載segment,快速,減小一次系統複製操做。memory_for_segments = total_memory - heap - direct_memory - jvm_overhead,segment可用的內存越小,mmap操做就會致使更多的內存換頁操做

參考資料

相關文章
相關標籤/搜索