#refer1:http://www.cnblogs.com/xd502djj/p/6408979.html
#refer2:https://www.cnblogs.com/tgzhu/p/6077846.html
Druid組成節點參考
1.RealtimeNode:?實時攝取數據、監聽輸入數據流
2.HistoricalNode:?對非實時數據進行處理存儲和查詢
3.BrokerNode:?接收來自外部客戶端的查詢和將查詢轉發到Realtime和Historical節點
4.CoordinatorNode:?監控Historical節點
5.IndexerNode:?負責索引服務
5.1. OverlordNode
5.2. MiddleManagerNode
#
一個Druid集群有各種類型的節點(Node)組成,每個節點都可以很好的處理相關邏輯的事情,這些節點包括對非實時數據進行處理存儲和查詢的Historical節點;實時攝取數據、監聽輸入數據流的Realtime節;監控Historical節點的Coordinator節點;接收來自外部客戶端的查詢和將查詢轉發到Realtime和Historical節點的Broker節點;負責索引服務的Indexer節點(包括Overlord節點和MiddleManager節點)。
#RealtimeNode
實時節點封裝了導入和查詢事件數據的功能,經由這些節點導入的事件數據可以立刻被查詢。
實時節點只關心一小段時間內的事件數據,并定期把這段時間內收集的這批不可變事件數據導入到Druid集群里面另外一個專門負責處理不可變的批量數據的節點中去。
實時節點通過Zookeeper的協調和Druid集群的其他節點協調工作。實時節點通過Zookeeper來宣布他們的在線狀態和他們提供的數據
實時節點為所有傳入的事件數據維持一個內存中的索引緩存, 隨著事件數據的傳入,這些索引會逐步遞增,并且這些索引是可以立即查詢的,查詢這些緩存于JVM的基于堆的緩存中的事件數據,Druid就表現得和行存儲一樣
為了避免堆溢出問題,實時節點會定期地、或者在達到設定的最大行限制的時候,把內存中的索引持久化到磁盤去
這個持久化進程會把保存于內存緩存中的數據轉換為基于列存儲的格式,所有持久化的索引都是不可變的,并且實時節點會加載這些索引到off-heap內存中使得它們可以繼續被查詢
上圖實時節點緩存事件數據到內存中的索引上,然后有規律的持久化到磁盤上。在轉移之前,持久化的索引會周期性地合并在一起。查詢會同時命中內存中的和已持久化的索引
所有的實時節點都會周期性的啟動后臺的計劃任務搜索本地的持久化索引,后臺計劃任務將這些持久化的索引合并到一起并生成一塊不可變的數據,這些數據塊包含了一段時間內的所有已經由實時節點導入的事件數據,我們稱這些數據塊為”Segment”。在傳送階段,實時節點將這些segment上傳到一個永久持久化的備份存儲中,通常是一個分布式文件系統,例如S3或者HDFS,Druid稱之為”Deep Storage”。
實時節點處理流程:導入、持久化、合并和傳送這些階段都是流動的,并且在這些處理階段中不會有任何數據的丟失,數據流圖如下:
節點啟動于13:47,并且只會接受當前小時和下一小時的事件數據。當事件數據開始導入后,節點會宣布它為13:00到14:00這個時間段的Segment數據提供服務
每10分鐘(這個時間間隔是可配置的),節點會將內存中的緩存數據刷到磁盤中進行持久化,在當前小時快結束的時候,節點會準備接收14:00到15:00的事件數據,一旦這個情況發生了,節點會準備好為下一個小時提供服務,并且會建立一個新的內存中的索引。
隨后,節點宣布它也為14:00到15:00這個時段提供一個segment服務。節點并不是馬上就合并13:00到14:00這個時段的持久化索引,而是會等待一個可配置的窗口時間,直到所有的13:00到14:00這個時間段的一些延遲數據的到來。這個窗口期的時間將事件數據因延遲而導致的數據丟失減低到最小。
在窗口期結束時,節點會合并13:00到14:00這個時段的所有持久化的索引合并到一個獨立的不可變的segment中,并將這個segment傳送走,一旦這個segment在Druid集群中的其他地方加載了并可以查詢了,實時節點會刷新它收集的13:00到14:00這個時段的數據的信息,并且宣布取消為這些數據提供服務。
#HistoricalNode
歷史節點封裝了加載和處理由實時節點創建的不可變數據塊(segment)的功能。在很多現實世界的工作流程中,大部分導入到Druid集群中的數據都是不可變的,因此,歷史節點通常是Druid集群中的主要工作組件。
歷史節點遵循shared-nothing的架構,因此節點間沒有單點問題。節點間是相互獨立的并且提供的服務也是簡單的,它們只需要知道如何加載、刪除和處理不可變的segment?(注:shared nothing architecture是一 種分布式計算架構,這種架構中不存在集中存儲的狀態,整個系統中沒有資源競爭,這種架構具有非常強的擴張性,在web應用中廣泛使用)
類似于實時節點,歷史節點在Zookeeper中通告它們的在線狀態和為哪些數據提供服務。加載和刪除segment的指令會通過Zookeeper來進行發布,指令會包含segment保存在deep storage的什么地方和怎么解壓、處理這些segment的相關信息
在歷史節點從deep storage下載某一segment之前,它會先檢查本地緩存信息中看segment是否已經存在于節點中,如果segment還不存在緩存中,歷史節點會從deep storage中下載segment到本地
一旦處理完成,這個segment就會在Zookeeper中進行通告。此時,這個segment就可以被查詢了。歷史節點的本地緩存也支持歷史節點的快速更新和重啟,在啟動的時候,該節點會檢查它的緩存,并為任何它找到的數據立刻進行服務的提供,如下圖:
歷史節點從deep storage下載不可變的segment。segment在可以被查詢之前必須要先加載到內存中
歷史節點可以支持讀一致性,因為它們只處理不可變的數據。不可變的數據塊同時支持一個簡單的并行模型:歷史節點可以以非阻塞的方式并發地去掃描和聚合不可變的數據塊
Tiers:?歷史節點可以分組到不同的tier中,哪些節點會被分到一個tier中是可配置的。Tier的目的是可以根據segment的重要程度來分配高或低的優先級來進行數據的分布。
可以為不同的tier配置不同的性能和容錯參數。例如,可以使用一批很多個核的CPU和大容量內存的節點來組成一個“熱點數據”的tier,這個“熱點數據”集群可以配置來用于下載更多經常被查詢的數據。
一個類似的”冷數據”集群可以使用一些性能要差一些的硬件來創建,“冷數據”集群可以只包含一些不是經常訪問的segment
可用性:?歷史節點依賴于Zookeeper來管理segment的加載和卸載。
如果Zookeeper變得不可用的時候,歷史節點就不再可以為新的數據提供服務和卸載過期的數據,因為是通過HTTP來為查詢提供服務的。
對于那些查詢它當前已經在提供服務的數據,歷史節點仍然可以進行響應。這意味著Zookeeper運行故障時不會影響那些已經存在于歷史節點的數據的可用性。
#BrokerNode
Broker節點扮演著歷史節點和實時節點的查詢路由的角色。
Broker節點知道發布于Zookeeper中的關于哪些segment是可查詢的和這些segment是保存在哪里的,Broker節點就可以將到來的查詢請求路由到正確的歷史節點或者是實時節點,
Broker節點也會將歷史節點和實時節點的局部結果進行合并,然后返回最終的合并后的結果給調用者
緩存:Broker節點包含一個支持LRU失效策略的緩存。這個緩存可以使用本地堆內存或者是一個外部的分布式 key/value 存儲,例如Memcached
每次Broker節點接收到查詢請求時,都會先將查詢映射到一組segment中去。這一組確定的segment的結果可能已經存在于緩存中,而不需要重新計算。
對于那些不存在于緩存的結果,Broker節點會將查詢轉發到正確的歷史節點和實時節點中去,一旦歷史節點返回結果,Broker節點會將這些結果緩存起來以供以后使用,這個過程如下圖所示
注意:實時數據永遠不會被緩存,因此查詢實時節點的數據的查詢請求總是會被轉發到實時節點上去。實時數據是不斷變化的,因此緩存實時數據是不可靠的
上圖:結果會為每一個segment緩存。查詢會合并緩存結果與歷史節點和實時節點的計算結果
緩存也可作為數據可用性的附加級別。在所有歷史節點都出現故障的情況下,對于那些命中已經在緩存中緩存了結果的查詢,仍然是可以返回查詢結果的
可用性:在所有的Zookeeper都中斷的情況下,數據仍然是可以查詢的。如果Broker節點不可以和Zookeeper進行通信了,它會使用它最后一次得到的整個集群的視圖來繼續將查詢請求轉發到歷史節點和實時節點,Broker節點假定集群的結構和Zookeeper中斷前是一致的。在實踐中,在我們診斷Zookeeper的故障的時候,這種可用性模型使得Druid集群可以繼續提供查詢服務,為我們爭取了更多的時間
?說明:通常在ShareNothing的架構中,如果一個節點變得不可用了,會有一個服務將下線的這個節點的數據搬遷到其他節點,但是如果這個節點下線后又立即重啟,而如果服務在一下線的時候就開始搬遷數據,是會產生跨集群的數據傳輸,實際上是沒有必要的。因為分布式文件系統對同一份數據會有多個副本,搬遷數據實際上是為了滿足副本數.而下線又重啟的節點上的數據不會有什么丟失的,因此短期的副本不足并不會影響整體的數據健康狀況.何況跨機器搬遷數據也需要一定的時間,何不如給定一段時間如果它真的死了,才開始搬遷。
#CoordinatorNode
主要負責數據的管理和在歷史節點上的分布。協調節點告訴歷史節點加載新數據、卸載過期數據、復制數據、和為了負載均衡移動數據。
Druid為了維持穩定的視圖,使用一個多版本的并發控制交換協議來管理不可變的segment。如果任何不可變的segment包含的數據已經被新的segment完全淘汰了,則過期的segment會從集群中卸載掉。
協調節點會經歷一個leader選舉的過程,來決定由一個獨立的節點來執行協調功能,其余的協調節點則作為冗余備份節點
協調節點會周期性的執行來確定集群的當前狀態,它通過在運行的時候對比集群的預期狀態和集群的實際狀態來做決定。和所有的Druid節點一樣,協調節點維持一個和Zookeeper的連接來獲取當前集群的信息
協調節點也維持一個與MySQL數據庫的連接,MySQL包含有更多的操作參數和配置信息。
其中一個存在于MySQL的關鍵信息就是歷史節點可以提供服務的所有segment的一個清單,這個表可以由任何可以創建segment的服務進行更新,例如實時節點。
MySQL數據庫中還包含一個Rule表來控制集群中segment的是如何創建、銷毀和復制
Rules:Rules管理歷史segment是如何在集群中加載和卸載的。
Rules指示segment應該如何分配到不同的歷史節點tier中,每一個tier中應該保存多少份segment的副本。
Rules還可能指示segment何時應該從集群中完全地卸載。Rules通常設定為一段時間,例如,一個用戶可能使用Rules來將最近一個月的有價值的segment載入到一個“熱點數據”的集群中,最近一年的有價值的數據載入到一個“冷數據”的集群中,而將更早時間前的數據都卸載掉。
協調節點從MySQL數據庫中的rule表加載一組rules。Rules可能被指定到一個特定的數據源,或者配置一組默認的rules。協調節點會循環所有可用segment并會匹配第一條適用于它的rule
負載均衡:在典型的生產環境中,查詢通常命中數十甚至上百個segment,由于每個歷史節點的資源是有限的,segment必須被分布到整個集群中,以確保集群的負載不會過于不平衡。
要確定最佳的負載分布,需要對查詢模式和速度有一定的了解。通常,查詢會覆蓋一個獨立數據源中最近的一段鄰近時間的一批segment。平均來說,查詢更小的segment則更快
這些查詢模式提出以更高的比率對歷史segment進行復制,把大的segment以時間相近的形式分散到多個不同的歷史節點中,并且使存在于不同數據源的segment集中在一起
為了使集群中segment達到最佳的分布和均衡,根據segment的數據源、新舊程度、和大小,開發了一個基于成本的優化程序
副本/復制(Replication):
協調節點可能會告訴不同的歷史節點加載同一個segment的副本。每一個歷史節點tier中副本的數量是完全可配置。
設置一個高級別容錯性的集群可以設置一個比較高數量的副本數。segment的副本被視為和原始segment一樣的,并使用相同的負載均衡算法
通過復制segment,單一歷史節點故障對于整個Druid集群來說是透明的,不會有任何影響
可用性:
協調節點有Zookeeper和MySQL這兩個額外的依賴,協調節點依賴Zookeeper來確定集群中有哪些歷史節點
如果Zookeeper變為不可用,協調節點將不可以再進行segment的分配、均衡和卸載指令的發送。不過,這些都不會影響數據的可用性
對于MySQL和Zookeeper響應失效的設計原則是一致的:如果協調節點一個額外的依賴響應失敗了,集群會維持現狀
Druid使用MySQL來存儲操作管理信息和關于segment如何存在于集群中的segment元數據。如果MySQL下線了,這些信息就在協調節點中變得不可用,不過這不代表數據不可用
如果協調節點不可以和MySQL進行通信,他們會停止分配新的segment和卸載過期的segment。在MySQL故障期間Broker節點、歷史節點、實時節點都是仍然可以查詢的
#
Druid架構介紹
Druid 由上面介紹的角色組成的構架圖:
查詢路徑:紅色箭頭:①客戶端向Broker發起請求,Broker會將請求路由到②實時節點和③歷史節點
Druid數據流轉:黑色箭頭:數據源包括實時流和批量數據. ④實時流經過索引直接寫到實時節點,⑤批量數據通過IndexService存儲到DeepStorage,⑥再由歷史節點加載. ⑦實時節點也可以將數據轉存到DeepStorage
Druid的集群依賴了ZooKeeper來維護數據拓撲. 每個組件都會與ZooKeeper交互,如下:
實時節點在轉存Segment到DeepStorage, 會寫入自己轉存了什么Segment
協調節點管理歷史節點,它負責從ZooKeeper中獲取要同步/下載的Segment,并指派任務給具體的歷史節點去完成
歷史節點從ZooKeeper中領取任務,任務完成后要將ZooKeeper條目刪除表示完成了任務
Broker節點根據ZooKeeper中的Segment所在的節點, 將查詢請求路由到指定的節點
對于一個查詢路由路徑,Broker只會將請求分發到實時節點和歷史節點, 因此元數據存儲和DeepStorage都不會參與查詢中(看做是后臺的進程).
MetaData Storage 與 Zookeeper
1. MetaStore和ZooKeeper中保存的信息是不一樣的,ZooKeeper中保存的是Segment屬于哪些節點,而MetaStore則是保存Segment的元數據信息。
2. 為了使得一個Segment存在于集群中,MetaStore存儲的記錄是關于Segment的自描述元數據: Segment的元數據,大小,所在的DeepStorage。
3. 元數據存儲的數據會被協調節點用來知道集群中可用的數據應該有哪些(Segment可以通過實時節點轉存或者批量數據直接寫入)。
#除了上面介紹的節點角色外,Druid還依賴于外部的三個組件:ZooKeeper, Metadata Storage, Deep Storage,數據與查詢流的交互圖如下:
① 實時數據寫入到實時節點,會創建索引結構的Segment;
② 實時節點的Segment經過一段時間會轉存到DeepStorage;
③ 元數據寫入MySQL; 實時節點轉存的Segment會在ZooKeeper中新增一條記錄;
④ 協調節點從MySQL獲取元數據,比如schema信息(維度列和指標列);
⑤ 協調節點監測ZK中有新分配/要刪除的Segment,寫入ZooKeeper信息:歷史節點需要加載/刪除Segment;
⑥ 歷史節點監測ZK, 從ZooKeeper中得到要執行任務的Segment;
⑦ 歷史節點從DeepStorage下載Segment并加載到內存/或者將已經保存的Segment刪除掉;
⑧ 歷史節點的Segment可以用于Broker的查詢路由。
#
由于各個節點和其他節點都是最小化解耦的,所以下面兩張圖分別表示實時節點和批量數據的流程:
數據從Kafka導入到實時節點,客戶端直接查詢實時節點的數據。
批量數據使用IndexService,接收Post請求的任務,直接產生Segment寫到DeepStorage里.DeepStorage中的數據只會被歷史節點使用。所以這里要啟動的服務有: IndexService(overlord), Historical, Coordinator(協調節點通知歷史節點下載Segment)。
#Druid分布式集群部署參考(測試)
2臺 Kafka
2臺realtime節點,并安裝了zookeeper節點
1臺broker節點
3臺historical節點,這幾臺機器比較獨立
1臺coordinator節點,并安裝了mysql服務,zookeeper節點
#deep storage ->?hdfs