Druid是一個開源的、分布式的、列存儲系統,特別適用於大數據上的(准)實時分析統計。且具有較好的穩定性(Highly Available)。 其相對比較輕量級,文檔非常完善,也比較容易上手。
Druid vs 其他系統
Druid vs Impala/Shark
Druid和Impala、Shark 的比較基本上可以歸結為需要設計什么樣的系統
Druid被設計用於:
- 一直在線的服務
- 獲取實時數據
- 處理slice-n-dice式的即時查詢
查詢速度不同:
- Druid是列存儲方式,數據經過壓縮加入到索引結構中,壓縮增加了RAM中的數據存儲能力,能夠使RAM適應更多的數據快速存取。索引結構意味着,當添加過濾器來查詢,Druid少做一些處理,將會查詢的更快。
- Impala/Shark可以認為是HDFS之上的后台程序緩存層。 但是他們沒有超越緩存功能,真正的提高查詢速度。
數據的獲取不同:
- Druid可以獲取實時數據。
- Impala/Shark是基於HDFS或者其他后備存儲,限制了數據獲取的速度。
查詢的形式不同:
- Druid支持時間序列和groupby樣式的查詢,但不支持join。
- Impala/Shark支持SQL樣式的查詢。
Druid vs Elasticsearch
Elasticsearch(ES) 是基於Apache Lucene的搜索服務器。它提供了全文搜索的模式,並提供了訪問原始事件級數據。 Elasticsearch還提供了分析和匯總支持。根據研究,ES在數據獲取和聚集用的資源比在Druid高。
Druid側重於OLAP工作流程。Druid是高性能(快速聚集和獲取)以較低的成本進行了優化,並支持廣泛的分析操作。Druid提供了結構化的事件數據的一些基本的搜索支持。
Segment: Druid中有個重要的數據單位叫segment,其是Druid通過bitmap indexing從raw data生成的(batch or realtime)。segment保證了查詢的速度。可以自己設置每個segment對應的數據粒度,這個應用中廣告流量查詢的最小粒度是天,所以每天的數據會被創建成一個segment。注意segment是不可修改的,如果需要修改,只能夠修改raw data,重新創建segment了。
架構
Druid本身包含5個組成部分:Broker nodes, Historical nodes, Realtime nodes, Coordinator Nodes和indexing services. 分別的作用如下:
- Broker nodes: 負責響應外部的查詢請求,通過查詢Zookeeper將請求划分成segments分別轉發給Historical和Real-time nodes,最終合並並返回查詢結果給外部;
- Historial nodes: 負責’Historical’ segments的存儲和查詢。其會從deep storage中load segments,並響應Broder nodes的請求。Historical nodes通常會在本機同步deep storage上的部分segments,所以即使deep storage不可訪問了,Historical nodes還是能serve其同步的segments的查詢;
- Real-time nodes: 用於存儲和查詢熱數據,會定期地將數據build成segments移到Historical nodes。一般會使用外部依賴kafka來提高realtime data ingestion的可用性。如果不需要實時ingest數據到cluter中,可以舍棄Real-time nodes,只定時地batch ingestion數據到deep storage;
- Coordinator nodes: 可以認為是Druid中的master,其通過Zookeeper管理Historical和Real-time nodes,且通過Mysql中的metadata管理Segments
- Druid中通常還會起一些indexing services用於數據導入,batch data和streaming data都可以通過給indexing services發請求來導入數據。
Druid還包含3個外部依賴
- Mysql:存儲Druid中的各種metadata(里面的數據都是Druid自身創建和插入的),包含3張表:”druid_config”(通常是空的), “druid_rules”(coordinator nodes使用的一些規則信息,比如哪個segment從哪個node去load)和“druid_segments”(存儲每個segment的metadata信息);
- Deep storage: 存儲segments,Druid目前已經支持本地磁盤,NFS掛載磁盤,HDFS,S3等。Deep Storage的數據有2個來源,一個是batch Ingestion, 另一個是real-time nodes;
- ZooKeeper: 被Druid用於管理當前cluster的狀態,比如記錄哪些segments從Real-time nodes移到了Historical nodes;
查詢
Druid的查詢是通過給Broker Nodes發送HTTP POST請求(也可以直接給Historical or Realtime Node),具體可見Druid官方文檔。查詢條件的描述是json文件,查詢的response也是json格式。Druid的查詢包含如下4種:
- Time Boundary Queries: 用於查詢全部數據的時間跨度
- groupBy Queries: 是Druid的最典型查詢方式,非常類似於Mysql的groupBy查詢。query body中幾個元素可以這么理解:
- “aggregation”: 對應mysql”select XX from”部分,即你想查哪些列的聚合結果;
- “dimensions”: 對應mysql”group by XX”,即你想基於哪些列做聚合;
- “filter”: 對應mysql”where XX”條件,即過濾條件;
- “granularity”: 數據聚合的粒度;
- Timeseries queries: 其統計滿足filter條件的”rows”上某幾列的聚合結果,相比”groupBy Queries”不指定基於哪幾列進行聚合,效率更高;
- TopN queries: 用於查詢某一列上按照某種metric排序的最常見的N個values;
本文小結
- Druid是一個開源的,分布式的,列存儲的,適用於實時數據分析的系統,文檔詳細,易於上手;
- Druid在設計時充分考慮到了Highly Available,各種nodes掛掉都不會使得druid停止工作(但是狀態會無法更新);
- Druid中的各個components之間耦合性低,如果不需要streaming data ingestion完全可以忽略realtime node;
- Druid的數據單位Segment是不可修改的,我們的做法是生成新的segments替換現有的;
- Druid使用Bitmap indexing加速column-store的查詢速度,使用了一個叫做CONCISE的算法來對bitmap indexing進行壓縮,使得生成的segments比原始文本文件小很多;
- 在我們的應用場景下(一共10幾台機器,數據大概100列,行數是億級別),平均查詢時間<2秒,是同樣機器數目的Mysql cluter的1/100 ~ 1/10;
- Druid的一些“局限”:
- Segment的不可修改性簡化了Druid的實現,但是如果你有修改數據的需求,必須重新創建segment,而bitmap indexing的過程是比較耗時的;
- Druid能接受的數據的格式相對簡單,比如不能處理嵌套結構的數據