概述
設計原則
- 快速查詢:部分數據的聚合 + 內存化 + 索引
- 水平擴展能力:分布式數據 + 并行化處理
- 實時分析:不可變的過去 + 只追加的未來
實時分析
Druid 提供了包含基于時間維度數據的存儲服務,并且任何一行都是歷史真實事件。所以設計之初約定事件一旦進入系統,就不可改變。
歷史數據存儲以segment數據文件的方式存儲在深度存儲系統(S3、HDFS)中。當需要查詢時,Druid在再把數據從深度存儲系統中裝載到內存中查詢使用。
技術特點
- 數據吞吐量大
- 支持流式數據攝入和實時索引服務
- 查詢靈活且快
- 社區支持力度大
基本概念
數據格式
- 數據源(DataSource):類似數據庫中表的概念
- 時間列(TimeStamp)
- 維度列(Dimension)
- 指標列(Metric)
如下表,時間是時間列,國家、平臺、語言是維度列,激活數、充值金額是指標列
時間 | 國家 | 平臺 | 語言 | 激活數 | 充值金額 |
---|---|---|---|---|---|
2017-08-04T00:00:00.000Z | SA | ios | en | 111 | 222.00 |
數據攝入
- 實時數據攝入
- 批處理數據攝入
數據查詢
- 原生查詢是采用JSON格式,通過HTTP傳送;
- 不支持標準的SQL語言查詢;
- 的社區也為我們提供了多種查詢方式(Python接口pydruid、R接口RDruid、JavaScript接口plywood、類SQL接口plyql、PHP接口druid-php等)
擴展性
- 分布式系統,采用Lambda架構,實時數據和批處理數據解耦;
- 實時處理面向寫多讀少優化
- 批處理面向讀多寫少優化
- Shared nothing架構,各個節點有自己的存儲和計算能力
- 使用zookeeper協調,使用mysql/postgresql提供元數據存儲
架構
總體架構
- 實時節點(Realtime Mode):即時攝入實時數據,及生成Segment數據文件;
- 歷史節點(Historical Mode):負責處理歷史數據存儲和查詢歷史數據(非實時),歷史節點從“deep storage”下載segments,將結果數據返回給查詢節點,歷史節點加載完segment通知Zookeeper,歷史節點使用Zookeeper監控需要加載或者刪除哪些新的;
- 查詢節點(Broker Mode):對外提供數據查詢服務,并同時從實時節點與歷史節點查詢數據,合并后返回給調用方;
- 協調節點(Coordinator Mode):負責劣勢節點的數據負載均衡,以及通過規則(Rule)管理數據的生命周期;
- 索引服務(Indexing Service): 索引服務節點由多個worker組成的集群,負責為加載批量的和實時的數據創建索引,并且允許對已經存在的數據進行修改。
索引服務:
- 統治節點(Overlord Node):索引服務的主節點,對外負責接受任務請求,對內負責將任務分解下去并下發到從節點(中間管理者)上;
- 中間管理者(Middle Managers):索引服務的工作節點,負責接收通知節點分配的任務,然后啟動相關的苦工接獨立的JVM完成具體的任務;
- 苦工(Peons):獨立的JVM,完成具體的任務。
索引服務的結構類似Hadoop Yarn 架構。
外部依賴
- 元數據庫(MetaStore):存儲Druid集群的原始數據信息,如:Segment相關信息(Msyql、PostgreSQL);
- 分布式協調服務(Zookeeper):幫助群集服務發現和維護當前數據的拓撲結構;
- 數據文件存儲庫(DeepStorage): 存放生成的Segement文件,并供歷史節點下載。
druid數據流程:

druid管理流程:

數據結構
DataSource
Druid的DataSource類似RDBMS中的表
- 時間列(TimeStamp):表明每行數據的時間值,默認使用UTC時間且精確到毫秒;
- 維度列(Dimension):用于標識數據行的各個類別信息;
- 指標列(Metric):用于聚合和計算的列。

Druid基于DataSource結構存儲數據時即可選擇對任意的指標進行聚合(Roll Up)操作。該操作主要基于維度列與時間范圍:
- 同維度列的值做聚合
- 對指定時間粒度內的值做聚合
DataSource聚合后數據:

Segment
DataSource是一個邏輯概念,Segment是數據的實際物理存儲格式。
Druid正是通過 Segment實現了對數據的橫縱向切割( Slice and Dice)操作。從數據按時間分布的角度來看,通過參數 segmentGranularity的設置, Druid將不同時間范圍內的數據存儲在不同的 Segment數據塊中,這便是所謂的數據橫向切割。這種設計為 Druid帶來一個顯而易見的優點:按時間范圍查詢數據時,僅需要訪問對應時間段內的這些 Segment數據塊,而不需要進行全表數據范圍查詢,這使效率得到了極大的提高。

同時,在 Segment中也面向列進行數據壓縮存儲,這便是所謂的數據縱向切割。而且在 Segment中使用了 Bitmap等技術對數據的訪問進行了優化
擴展系統
實時節點(Realtime Mode)
實時節點(Realtime Node) 負責即時攝入實時數據,以及生成Segment數據文件,并提供實時數據的查詢。
- 存儲:metadata(元數據)寫入MySQL,在ZooKeeper中新增一條記錄S。egment定期會轉存到DeepStorage;
- 查詢:提供實時查詢索引,響應broker的查詢。
master即為協調節點(coordinator)

- 實時節點緩存事件數據到內存中的索引上,然后有規律的持久化到磁盤上。在轉移之前,持久化的索引會周期性地合并在一起。(查詢會同時命中內存中的和已持久化的索引。)
- 實時節點周期性的啟動后臺的計劃任務搜索本地的持久化索引,后臺計劃任務將這些持久化的索引合并到一起并生成一塊不可變的數據,這些數據塊包含了
- 一段時間內的所有已經由實時節點導入的事件數據,稱這些數據塊為”Segment”。
- 在傳送階段,實時節點將這些segment上傳到一個永久持久化的備份存儲中,即Deep Storage
歷史節點(Historical Mode)
歷史節點負責加載已生成好的數據文件以及提供數據查詢。

歷史節點在從下載segment前,會從本地緩存檢查是否存在,如果不存在才從hdfs下載。下載完成之后,會根據zk獲取到的壓縮信息進行解壓處理并加載到內存,提供查詢服務。
數據分層
可以通過配置給歷史節點劃分不同的層(Tier),然后在coordinator配置規則來加載指定數據源到某個層。這樣可以實現冷熱數據劃分處理,熱數據查詢多存量小,采用更好的cpu和內存機型配置,冷數據查詢少存量大,采用更大的硬盤機型配置
查詢節點(Broker Mode)
查詢節點對外提供數據查詢服務,并同時從實時節點與歷史節點查詢數據,合并后返回調用方。
緩存使用
Druid使用Cache機制提高查詢效率。
- 外部緩存,如:Memcached
- 本地緩存,如:查詢節點或歷史節點的內存
協調節點(Coordinator Mode)
協調節點負責 歷史節點的負載均衡,并通過規則管理數據的生命周期。
- 規則(Rules):每分鐘從mysql拉取druid_rules和druid_segments,rules用來告知historical將如何load和drop索引文件,coordinator會讀取這些rules,然后修改zk,通知historical加載刪除指定的segment,這些都可以在coordinator的UI配置;
- 負載均衡:根據zk中每個historical node負責的segment量,做負載均衡;
- 副本(replication):在coordinator的UI中配置rules時,可以同時配置加載segment的備份數量,這些備份數量會以load balance的形式,分配到多個historical上面。這個備份數量與hdfs的segment備份數量不一樣,hdfs那個保證深度存儲的數據不會丟失,historical上面備份是為了保證當某個historical掛掉的時候,其他存儲了備份segment的節點能接著提供查詢服務。
索引服務
索引服務包含一組組件,并以主從結構作為其架構方式。其中統治節點(Overlord Node)為主節點,中間管理者(Middle Manager)為從節點。

- 統治節點:接收tranquility請求的實時索引task,選擇slot空閑最多的middle-manager,通過zk將task分配給middle-manager,填滿為止;
- 中間管理者:通過zk獲取task,啟動本地進程peon執行task;
- 苦工(peon):執行task,完成索引建立。peon本身還負責索引查詢服務。