1. 程式人生 > >Druid架構概覽

Druid架構概覽

什麼是Druid

Druid是一個高效的資料查詢系統,主要解決的是對於大量的基於時序的資料進行聚合查詢。資料可以實時攝入,進入到Druid後立即可查,同時資料是幾乎是不可變。通常是基於時序的事實事件,事實發生後進入Druid,外部系統就可以對該事實進行查詢。

Druid系統架構

Druid是一組系統,按照職責分成不同的角色。目前存在五種節點型別:

  • Historical: 歷史節點的職責主要是對歷史的資料進行儲存和查詢,歷史節點從Deep Storage下載Segment,然後響應Broker對於Segment的查詢將查詢結果返回給Broker節點,它們通過Zookeeper來宣告自己儲存的節點,同時也通過zookeeper來監聽載入或刪除Segment的訊號。
  • Coordinator:協調節點監測一組歷史節點來保證資料的可用和冗餘。協調節點讀取元資料儲存來確定哪些Segment需要load到叢集中,通過zk來感知Historical節點的存在,通過在Zookeeper上建立entry來和Historical節點通訊來告訴他們載入或者刪除Segment
  • Broker:節點接收外部客戶端的查詢,並且將查詢路由到歷史節點和實時節點。當Broker收到返回的結果的時候,它將結果merge起來然後返回給呼叫者。Broker通過Zook來感知實時節點和歷史節點的存在。
  • Indexing Service: 索引服務是一些worker用來從實時獲取資料或者批量插入資料。
  • Realtime:獲取實時資料

下面這張圖片展示了一次查詢資料在整個架構中的流向

Druid資料流向

除了上述五個節點,Druid還有三個外部依賴:

  • Zookeeper叢集
  • 元資料儲存例項:Mysql
  • Deep Storage:HDFS

Segments

Druid 把它的索引儲存到一個Segment檔案中,Segment檔案是通過時間來分割的。

Segment資料結構

對於攝入到Druid的資料的列,主要分三種類型,時間列,指標列和維度列。如下圖

示例資料

對於時間列和指標列處理比較簡單,直接用LZ4壓縮存起來就ok,一旦查詢知道去找哪幾行,只需要將它們解壓,然後用相應的操作符來操作它們就可以了。維度列就沒那麼簡單了,因為它們需要被過濾和聚合,因此每個維度需要下面三個資料結構。

  1. 一個map,Key是維度的值,值是一個整型的id
  2. 一個儲存列的值得列表,用1中的map編碼的list
  3. 對於列中的每個值對應一個bitmap,這個bitmap用來指示哪些行包含這個個值。

對於上圖的Page列,它的儲存是這樣的

1: 字典
{
    "Justin BIeber": 0,
    "Ke$ha":         1
}

2. 值的列表
[0,
 0,
 1,
 1]

3. bitMap
value="Justin Bieber": [1, 1, 0, 0]
value="Ke$ha":         [0, 0, 1, 1]

歷史節點

每個歷史節點維持一個和Zookeeper的長連線監測一組path來獲取新的Segment資訊。歷史節點互相不進行通訊,他們依靠zk來等待協調節點來協調。
協調節點負責把新的Segment分發給歷史節點,協調節點通過在zk的指定路徑下建立一個entry來向歷史節點做分發。
當歷史節點發現一個新的entry出現在path中,它首先會檢查本地檔案快取看有有沒Segment資訊,如果沒有Segment資訊,歷史節點會從zk上下載新的Segment的元資訊。Segment的元資訊包括Segment存在Deep Storage的位置和如何解壓和處理Segment。一旦一個歷史節點完成對一個Segment的處理,這個歷史節點會在zk上的一個路徑宣告對這個Segment提供查詢服務,此刻這個Segment就可以查詢了。

查詢節點

Broker節點負責將查詢路由到歷史節點和實時節點,Broker節點通過zk來知道哪些Segment存在哪個節點上。Broker也會把查詢的結果進行Merge
大多數Druid查詢包含一個區間物件,這個物件用來指定查詢所要查的區間段。Druid的Segment也通過時間段進行分割散落在整個叢集中。假設有一個簡單的資料來源,這個資料來源有七個Segment,每個Segment包含一週中的某一天的資料。任何一個時間範圍超過一天的查詢都會落到不止一個Segment上。這些Segment可能分佈在叢集中不同的節點上。因此這種查詢就會涉及到多個節點。
為了確定傳送到哪個節點上,Broker會從Historial和RealTime的節點來獲取他們提供查詢的Segment的資訊,然後構建一個時間軸,當收到特定的時間區間的查詢時,Broker通過時間軸來選擇節點。
Broker節點會維護一個LRU快取,快取存著每個Segment的結果,快取可以是一個本地的快取或者多個節點共用的外部的快取如 memcached。當Broker收到查詢時候,它首先將查詢對映成一堆Segment的查詢,其中的一個子集的結果可能已經存在快取中,他們可以直接從快取中拉出來,那些沒在快取中的將被髮送到相應節點。

協調節點

協調節點負責Segment的管理和分發,協調節點指揮歷史節點來載入或者刪除Segment,以及Segment的冗餘和平衡Segment。協調節點會週期性的進行掃描,每次掃描會根據叢集當前的狀態來決定進一步的動作。和歷史節點和Broker一樣,協調節點通過zk來獲取Segment資訊,同時協調節點還通過資料庫來獲取可用的Segment資訊和規則。在一個Segment提供查詢之前,可用的歷史節點會按照容量去排序,容量最小的具有最高的優先順序,協調節點就會讓它去載入這個Segment然後提供服務。

  • 清理Segment,Druid會將叢集中的Segment和資料庫中的Segment進行對比,如果叢集有的的資料庫中沒有的會被清理掉。同事那些老的被新的替換的Segment也會被清理掉。
  • Segment可用性, 歷史節點可能因為某種原因不可用,協調節點會發現節點不可用了,會將這個節點上的Segment轉移到其他的節點。Segment不會立即被轉移,如果在配置的時間段內節點恢復了,歷史節點會從本地快取載入Segment。恢復服務
  • Segment負載均衡,協調節點會找到Segment最多的節點和Segment最少的節點,當他們的比例超過一個設定的值的時候,協調節點會從Segment最多的節點轉移到Segment最少的節點。

索引服務

索引服務是一個高可用的,分散式的服務來執行索引相關的Task。索引服務會建立或者銷燬Segment。索引服務是一個Master/Slave架構。索引服務是三個元件的集合

  • peon元件用來跑索引任務。
  • Middle Manager元件用來管理peons
  • Overlord向MiddleManager分發任務。

索引服務

索引服務

Overlord節點負責接受任務,協調任務分發,建立鎖,和返回狀態給呼叫者。Overlord節點可以以本地模式或者遠端模式執行。本地模式會直接建立Peon,遠端模式會通過Middle Manager建立任務。

實時節點

實時節點提供實時索引服務,通過實時節點索引的資料立即可查。實時節點會週期性的構建Segment,並且把這些Segment推到歷史節點並修改元資料。

實時節點