Druid是一個(gè)專門針對(duì)事件數(shù)據(jù)的OLAP查詢而設(shè)計(jì)的開源數(shù)據(jù)存儲(chǔ)系統(tǒng)。此頁(yè)面旨在為讀者介紹關(guān)于Druid存儲(chǔ)數(shù)據(jù)的高級(jí)概述芜果,以及Druid集群的架構(gòu)爱态。
數(shù)據(jù)
我們從一個(gè)在線廣告的示例數(shù)據(jù)集開始討論:
timestamp publisher advertiser gender country click price
2011-01-01T01:01:35Z bieberfever.com google.com Male USA 0 0.65
2011-01-01T01:03:63Z bieberfever.com google.com Male USA 0 0.62
2011-01-01T01:04:51Z bieberfever.com google.com Male USA 1 0.45
2011-01-01T01:00:00Z ultratrimfast.com google.com Female UK 0 0.87
2011-01-01T02:00:00Z ultratrimfast.com google.com Female UK 0 0.99
2011-01-01T02:00:00Z ultratrimfast.com google.com Female UK 1 1.53
熟悉OLAP的同學(xué)應(yīng)該對(duì)這些概念肯定不會(huì)陌生衬潦,Druid也把數(shù)據(jù)集分為三個(gè)部分:
- Timestamp column(時(shí)間字段):將時(shí)間字段單獨(dú)處理,是因?yàn)镈ruid的所有查詢都是圍繞時(shí)間軸進(jìn)行的隆圆。
- Dimension columns(維度字段): 維度字段是數(shù)據(jù)的屬性漱挚,一般被用來(lái)做數(shù)據(jù)的過(guò)濾。在示例數(shù)據(jù)集中有四個(gè)維度:publisher渺氧、advertiser旨涝、gender和 country。它們各自代表了我們用來(lái)分割數(shù)據(jù)的軸。
- Metric columns(度量字段):度量字段是用來(lái)做數(shù)據(jù)的聚合計(jì)算的白华。在示例中慨默, click和price是倆個(gè)度量。度量是可以衡量的數(shù)據(jù)弧腥,一般可以做count厦取、sum等操作。在OLAP術(shù)語(yǔ)中也叫measures管搪。
Roll-up
在海量數(shù)據(jù)處理中虾攻,一般對(duì)于單條的細(xì)分?jǐn)?shù)據(jù)并不感興趣,因?yàn)榇嬖跀?shù)萬(wàn)億計(jì)這樣的事件更鲁。然而這類數(shù)據(jù)的統(tǒng)計(jì)匯總是很有用的霎箍,Druid通過(guò)roll-up過(guò)程的處理,使數(shù)據(jù)在攝取加載階段就做了匯總處理澡为。Roll-up(匯總)是在維度過(guò)濾之前就做的第一級(jí)聚合操作漂坏。相等于如下偽代碼:
GROUP BY timestamp, publisher, advertiser, gender, country
:: impressions = COUNT(1), clicks = SUM(click), revenue = SUM(price)
原始數(shù)據(jù)壓縮聚合之后就是這個(gè)樣子:
timestamp publisher advertiser gender country impressions clicks revenue
2011-01-01T01:00:00Z ultratrimfast.com google.com Male USA 1800 25 15.70
2011-01-01T01:00:00Z bieberfever.com google.com Male USA 2912 42 29.18
2011-01-01T02:00:00Z ultratrimfast.com google.com Male UK 1953 17 17.31
2011-01-01T02:00:00Z bieberfever.com google.com Male UK 3194 170 34.01
可以看到,通過(guò)roll-up匯總數(shù)據(jù)后可以大大減少需要存儲(chǔ)的數(shù)據(jù)量(高達(dá)100倍)媒至。Druid在接收數(shù)據(jù)的時(shí)候匯總數(shù)據(jù)顶别,以最小化需要存儲(chǔ)的原始數(shù)據(jù)量。但是這種存儲(chǔ)減少是有代價(jià)的拒啰,當(dāng)我們r(jià)oll up數(shù)據(jù)后驯绎,就沒辦法再查詢?cè)敿?xì)數(shù)據(jù)了。換句話說(shuō)roll-up后的粒度就是你能夠探索數(shù)據(jù)的最小粒度图呢,事件被分配到這個(gè)粒度。因此骗随,Druid攝取規(guī)范將此粒度定義為數(shù)據(jù)的queryGranularity蛤织, 支持的最低queryGranularity是毫秒。
Sharding the Data
Druid的數(shù)據(jù)分片稱為 segments鸿染,druid總是最先通過(guò)時(shí)間來(lái)分片指蚜,上面例子中我們聚合后的數(shù)據(jù),可以按小時(shí)分為倆分片:
Segment sampleData_2011-01-01T01:00:00:00Z_2011-01-01T02:00:00:00Z_v1_0包含
2011-01-01T01:00:00Z ultratrimfast.com google.com Male USA 1800 25 15.70
2011-01-01T01:00:00Z bieberfever.com google.com Male USA 2912 42 29.18
Segment sampleData_2011-01-01T02:00:00:00Z_2011-01-01T03:00:00:00Z_v1_0包含
2011-01-01T02:00:00Z ultratrimfast.com google.com Male UK 1953 17 17.31
2011-01-01T02:00:00Z bieberfever.com google.com Male UK 3194 170 34.01
segments是一個(gè)包含數(shù)據(jù)的獨(dú)立容器涨椒,內(nèi)部數(shù)據(jù)以時(shí)間分割摊鸡。segments為聚合的列做索引,數(shù)據(jù)依賴索引蚕冬,按列方式存儲(chǔ)免猾。 所以druid得查詢就轉(zhuǎn)為了如何掃描segments了。
segment 由datasource(數(shù)據(jù)源)囤热、interval(間隔)猎提、version(版本號(hào))和一個(gè)可選的分區(qū)號(hào)唯一的確定。 例如上面例子中旁蔼,我們的segment的名字就是這種格式dataSource_interval_version_partitionNumber锨苏。
Indexing the Data
Druid能夠取得這樣的查詢速度疙教,主要取決于數(shù)據(jù)的存儲(chǔ)方式。借鑒google等搜索引擎的思路伞租,Druid生成不可變的數(shù)據(jù)快照贞谓,存儲(chǔ)在針對(duì)分析查詢高度優(yōu)化的數(shù)據(jù)結(jié)構(gòu)中。
Druid是列式存儲(chǔ)也就意味著每一個(gè)列都是單獨(dú)存儲(chǔ)的葵诈。Druid查詢時(shí)只會(huì)使用到與查詢相關(guān)的列裸弦,而且Druid很好的支持了在查詢時(shí)只掃描其需要的。不同的列可以采用不同的壓縮方法驯击,也能夠建立與它們相關(guān)的不同索引烁兰。
Druid在每一個(gè)分片級(jí)別(segment)建立索引。
Loading the Data
Druid有實(shí)時(shí)和批量?jī)煞N方式進(jìn)行數(shù)據(jù)攝取徊都。Druid中實(shí)時(shí)數(shù)據(jù)攝取方式是盡力而為沪斟。Druid暫時(shí)實(shí)時(shí)攝取暫時(shí)無(wú)法支持正好一次(Exactly once),當(dāng)然在后續(xù)版本計(jì)劃中會(huì)盡量去支持暇矫。通過(guò)批量創(chuàng)建能夠準(zhǔn)確映射到攝取數(shù)據(jù)的段主之,批量攝取提供了正好一次的保證。使用Druid的通用方式是用實(shí)時(shí)管道獲取實(shí)時(shí)數(shù)據(jù)李根,用批量管道處理副本數(shù)據(jù)槽奕。
Querying the Data
Druid的本地查詢語(yǔ)言是JSON通過(guò)HTTP,雖然社區(qū)在眾多的語(yǔ)言中提供了查詢庫(kù)房轿,包括SQL查詢貢獻(xiàn)庫(kù)粤攒。
Druid設(shè)計(jì)用于單表操作,目前不支持join操作囱持。因?yàn)榧虞d到Druid中的數(shù)據(jù)需要規(guī)范化夯接,許多產(chǎn)品準(zhǔn)備在數(shù)據(jù)ETL(Extract-Transform-Load)階段進(jìn)行join。
The Druid Cluster
Druid集群是由不同類型節(jié)點(diǎn)組成的纷妆,每個(gè)節(jié)點(diǎn)各司其職:
- Historical Nodes 歷史節(jié)點(diǎn)通常構(gòu)成Druid集群的骨干盔几,歷史節(jié)點(diǎn)在本地下載不可變的段,并對(duì)這些段進(jìn)行查詢掩幢。這些節(jié)點(diǎn)有一個(gè)無(wú)共享的體系結(jié)構(gòu)逊拍,并知道如何加載數(shù)據(jù)段、丟棄數(shù)據(jù)段,并對(duì)數(shù)據(jù)段進(jìn)行查詢际邻。
- Broker Nodes Broker節(jié)點(diǎn)是客戶端和應(yīng)用從Druid查詢獲取數(shù)據(jù)的地方芯丧。Broker節(jié)點(diǎn)負(fù)責(zé)分配查詢并且收集和合并結(jié)果,Broker節(jié)點(diǎn)知道哪些段放在哪里世曾。
- Coordinator Nodes Coordinator節(jié)點(diǎn)負(fù)責(zé)管理集群中歷史節(jié)點(diǎn)的段注整,協(xié)調(diào)器節(jié)點(diǎn)告訴歷史節(jié)點(diǎn)加載新的段、刪除舊的段并且移動(dòng)段來(lái)達(dá)到負(fù)載均衡。
- Real-time Processing Druid中的實(shí)時(shí)處理可以使用獨(dú)立的實(shí)時(shí)節(jié)點(diǎn)或使用索引服務(wù)來(lái)完成肿轨。實(shí)時(shí)邏輯在這兩個(gè)服務(wù)之間是共同的寿冕。實(shí)時(shí)處理包括接收數(shù)據(jù)、索引數(shù)據(jù)(創(chuàng)建數(shù)據(jù)段)和將數(shù)據(jù)段傳輸?shù)綒v史節(jié)點(diǎn)椒袍。通過(guò)實(shí)時(shí)處理邏輯接收數(shù)據(jù)驼唱,數(shù)據(jù)就是可查詢的。切換過(guò)程也是無(wú)損的驹暑,數(shù)據(jù)在整個(gè)過(guò)程中保持可查詢玫恳。
外部依賴
Druid對(duì)集群操作有幾個(gè)外部依賴關(guān)系。
- Zookeeper Druid依賴zookeeper進(jìn)行集群內(nèi)部通信优俘。
- Metadata Storage Druid依賴元數(shù)據(jù)存儲(chǔ)來(lái)存儲(chǔ)段和配置的元數(shù)據(jù)京办。創(chuàng)建段的服務(wù)向元數(shù)據(jù)存儲(chǔ)寫入新條目,并且協(xié)調(diào)器節(jié)點(diǎn)監(jiān)視元數(shù)據(jù)存儲(chǔ)以知道何時(shí)需要加載新數(shù)據(jù)或需要丟棄舊數(shù)據(jù)帆焕。元數(shù)據(jù)存儲(chǔ)不包含在查詢路徑中惭婿。MySQL和PostgreSQL是生產(chǎn)系統(tǒng)中常用的元數(shù)據(jù)存儲(chǔ)數(shù)據(jù)庫(kù)。當(dāng)在單機(jī)系統(tǒng)上運(yùn)行所有Druid節(jié)點(diǎn)叶雹,可以使用Derby 數(shù)據(jù)庫(kù)财饥。
- Deep Storage 深度存儲(chǔ)用作段的永久備份。創(chuàng)建段的服務(wù)將段上傳到深度存儲(chǔ)折晦,歷史節(jié)點(diǎn)從深度節(jié)點(diǎn)上下載段钥星。深度存儲(chǔ)也不包含在查詢路徑里。S3和HDFS是流行的深度存儲(chǔ)方式满着。
高可用性
Druid設(shè)計(jì)避免了單點(diǎn)故障谦炒。不同類型的節(jié)點(diǎn)故障并不會(huì)影響其他類型節(jié)點(diǎn)的服務(wù)。為了運(yùn)行高可用的Druid集群风喇,需要每個(gè)節(jié)點(diǎn)類型至少2個(gè)節(jié)點(diǎn)宁改。