1. 程式人生 > >Apache Druid 的叢集設計與工作流程

Apache Druid 的叢集設計與工作流程

> 導讀:本文將描述 Apache Druid 的基本叢集架構,說明架構中各程序的作用。並從資料寫入和資料查詢兩個角度來說明 Druid 架構的工作流程。 關注公眾號 MageByte,設定星標點「在看」是我們創造好文的動力。公眾號後臺回覆 “加群” 進入技術交流群獲更多技術成長。 Druid 是多程序架構,每種程序型別都可以獨立配置,獨立擴充套件。這樣可以為叢集提供最大的靈活度。這種設計還提供了強失效容忍:一個失效的元件不會立即影響另外的元件。 下面我們來深入瞭解 Druid 有哪些程序型別,每種程序又在整個叢集中扮演什麼角色。 ## 程序和服務(Process and Servers) Druid 有多種程序型別,如下: - **Coordinator**程序在叢集中負責管理資料可用。 - **Overlord**程序控制資料攝入的資源負載分配。 - **Broker**程序處理外部客戶端的查詢。 - **Router**程序是可選的,它可以路由請求到 Brokers,Coordinator,和 Overlord。 - **Historical**程序儲存可查詢的資料。 - **MiddleManager**程序負責資料攝入。 你可以以任何方式來部署上面的程序。但是為了易於運維,官方建議以下面三種服務型別來組織程序:Master、Query 和 Data。 - **Master:**執行 Coordinator 和 Overlord 程序,管理資料可用和資料寫入。 - **Query:** 執行 Broker 和可選的 Router 程序,負責處理外部查詢請求。 - **Data:**執行 Historical 和 MiddleManager 程序,負責執行資料寫入任務並存儲可查詢的資料。 ## 外部依賴(External dependencies) 除了內建的程序型別,Druid 還有三個外部依賴項。 ### Deep storage 共享檔案儲存,只要配置成允許 Druid 訪問即可。在叢集部署中,通常使用分散式儲存(如 S3 或 HDFS)或掛載網路檔案系統。在單機部署中,通常使用本地磁碟。Druid 使用 Deep Storage 儲存寫入叢集的資料。 Druid 僅將 Deep Storage 用作**資料的備份**,並作為 Druid**程序間在後臺的資料傳輸方式**。要響應查詢,Historical 程序並不從 Deep Storage 上讀取資料,在任何查詢之前,先從本地磁碟查詢已經存在的資料。這意味著,Druid 在查詢時並不需要訪問 Deep Storage,這樣就可以得到最優的查詢延遲。這也意味著,在 Deep Storage 和 Historical 程序間你必須有足夠的磁碟空間來儲存你計劃載入的資料。 Deep Storage 是 Druid 彈性、容錯設計的重要組成部分。如果 Druid 單機程序本地資料丟失,可以從 Deep Storage 恢復資料。 ### Metadata storage 元資料儲存,儲存各種共享的系統元資料,如 segment 可用性資訊和 task 資訊。在叢集部署中,通常使用傳統的 RDBMS,如 PostgreSQL 或 MySQL。在單機部署中,通常使用本地儲存,如 Apache Derby 資料庫。 ### Zookeeper 用來進行內部服務發現,協調,和主選舉。 ## 架構圖(Architecture diagram) 下圖可以看出使用官方建議的 Master/Query/Data 服務部署方式,查詢和寫入資料是如何進行的: ![druid-architecture](https://magebyte.oss-cn-shenzhen.aliyuncs.com/druid/druid-architecture.png) ## 儲存設計(Storage design) ### Datasources and segments Druid 資料儲存在"datasources"中,它就像 RDBMS 中的 table。每一個 datasources 通過時間分割槽,或通過其他屬性進行分割槽。每一個時間範圍稱之為"chunk"(比如,一天一個,如果你的 datasource 使用 day 分割槽)。在 chunk 中,資料被分割槽進一個或多個"segments"中。每一個 segment 是一個單獨的檔案,通常包含數百萬行資料。一旦 segment 被儲存進 chunks,其組織方式將如以下時間線所示: ![druid-timeline](https://magebyte.oss-cn-shenzhen.aliyuncs.com/druid/druid-timeline.png) 一個 datasource 也許只有一個,也可能有數十萬甚至上百萬個 segment。每個 segment 生命週期開始於 MiddleManager 建立時,剛被建立時,segment 是可變和未提交的。segment 構建過程包含以下幾步,旨在生成結構緊湊並支援快速查詢的資料檔案。 - 轉換成列格式 - 使用 bitmap 建立索引 - 使用各種演算法壓縮資料 - 為 String 列做字典編碼,用最小化 id 儲存 - 對 bitmap 索引做 bitmap 壓縮 - 對所有列做型別感知壓縮 segment 定時提交和釋出。此時,資料被寫入 Deep Storage,並且再不可變,並從 MiddleManagers 程序遷移至 Historical 程序中。一個關於 segment 的 entry 將寫入 metadata storage。這個 entry 是關於 segment 的元資料的自描述資訊,包含如 segment 的資料模式,大小,Deep Storage 地址等資訊。這些資訊讓 Coordinator 知道叢集中哪些資料是可用的。 ### 索引和移交(Indexing and handoff) indexing 是每個 segment 建立的機制。handoff 是資料被髮布並開始可以被 Historical 程序處理的機制。這機制在 indexing 側的工作順序如下: 1. 啟動一個 indexing task 並構建一個新的 segment。在構建之前必須先確定其標識。對於一個追加任務(如 kafka 任務,或 append 模式任務)可以呼叫 Overlord 的"allocate"API 來將一個潛在的新分割槽加入到一個已經存在的 segment 中。對於一個覆寫任務(如 Hadoop 任務,或非 append 模式 index 任務) 將為 interval 建立新版本號和新 segment。 2. 如果 indexing 任務是實時任務(如 Kafka 任務),此時 segment 可以立即被查詢。資料是可用的,但還是未釋出狀態。 3. 當 indexing 任務完成讀取 segment 資料時,它將資料推送到 Deep Storage 上,並通過向 metadata store 寫一個記錄來發布資料。 4. 如果 indexing 任務是實時任務,此時,它將等待 Historical 程序載入這個 segment。如果 indexing 任務不是實時任務,就立即退出。 這機制在 Coordinator/Historical 側的工作如下: 1. Coordinator 定期從 metadata storage 拉取已經發布的 segments(預設,每分鐘執行)。 2. 當 Coordinate 發現已釋出但不可用的 segment 時,它將選擇一個 Historical 程序去載入 segment,並指示 Historical 該做什麼。 3. Historical 載入 segment 併為其提供服務。 4. 此時,如果 indexing 任務還在等待資料移交,就可以退出。 資料寫入(indexing)和移交(handoff): ![](https://magebyte.oss-cn-shenzhen.aliyuncs.com/druid/druid-indexing.jpg) ### 段標識(Segment identifiers) Segment 標識由下面四部分組成: - Datasource 名稱。 - 時間間隔(segment 包含的時間間隔,對應資料攝入時`segmentGranularity`指定引數)。 - 版本號(通常是 ISO8601 時間戳,對應 segment 首次生成時的時間)。 - 分割槽號(整數,在 datasource+interval+version 中唯一,不一定是連續的)。 例如,這是 datasource 為`clarity-cloud0`,時間段為`2018-05-21T16:00:00.000Z/2018-05-21T17:00:00.000Z`,版本號為`2018-05-21T15:56:09.909Z`,分割槽號為 1 的識別符號: ``` clarity-cloud0_2018-05-21T16:00:00.000Z_2018-05-21T17:00:00.000Z_2018-05-21T15:56:09.909Z_1 ``` 分割槽號為 0(塊中的第一個分割槽)的 segment 省略了分割槽號,如以下示例所示,它是與前一個分割槽在同一時間塊中的 segment,但分割槽號為 0 而不是 1: ``` clarity-cloud0_2018-05-21T16:00:00.000Z_2018-05-21T17:00:00.000Z_2018-05-21T15:56:09.909Z ``` ### 段版本控制(segment versioning) 你可能想知道上一節中描述的“版本號”是什麼。 Druid 支援批處理模式覆寫。在 Driud 中,如果你要做的只是追加資料,那麼每個時間塊只有一個版本。但是,當你覆蓋資料時,在幕後發生的事情是使用相同的資料來源,相同的時間間隔,但版本號更高的方式建立了一組新的 segment。這向 Druid 系統的其餘部分發出訊號,表明應從群集中刪除較舊的版本,而應使用新版本替換它。 對於使用者而言,切換似乎是瞬間發生的,因為 Druid 通過先載入新資料(但不允許對其進行查詢)來處理此問題,然後在所有新資料載入完畢後,立即將新查詢切換到新 segment。然後,它在幾分鐘後刪除舊 segment。 ### 段(segment)生命週期 每個 segment 的生命週期都涉及以下三個主要領域: 1. **元資料儲存區:**一旦構建完 segment,就將 segment 元資料(小的 JSON 資料,通常不超過幾個 KB)儲存在 `元資料儲存區`中。將 segmnet 的記錄插入元資料儲存的操作稱為*釋出*。然後將元資料中的`use`布林值設定成`可用`。由實時任務建立的 segment 將在釋出之前可用,因為它們僅在 segment 完成時才釋出,並且不接受任何其他資料。 2. **深度儲存:**segment 資料構建完成後,並在將元資料釋出到元資料儲存之前,立即將 segment 資料檔案推送到深度儲存。 3. **查詢的可用性:**segment 可用於在某些 Druid 資料伺服器上進行查詢,例如實時任務或**Historical**程序。 你可以使用 Druid SQL [`sys.segments`表](https://druid.apache.org/docs/latest/querying/sql.html#segments-table)檢查當前 segment 的狀態 。它包括以下標誌: - `is_published`:如果 segment 元資料已釋出到儲存的元資料中,`used`則為 true,此值也為 true。 - `is_available`:如果該 segment 當前可用於實時任務或**Historical**查詢,則為 True。 - `is_realtime`:如果 segment 在實時任務上可用,則為 true 。對於使用實時寫入的資料來源,通常會先設定成`true`,然後隨著 segment 的釋出和移交而變成`false`。 - `is_overshadowed`:如果該 segment 已釋出(`used`設定為 true)並且被其他一些已釋出的 segment 完全覆蓋,則為 true。通常,這是一個過渡狀態,處於此狀態的 segment 很快就會將其`used`標誌自動設定為 false。 ## 查詢處理 查詢首先進入`Broker`程序,`Broker`將得出哪些 segment 具有與該查詢有關的資料(segment 列表始終按時間規劃,也可以根據其他屬性來規劃,這取決於資料來源的分割槽方式),然後,`Broker`將確定哪些 `Historical` 和 `MiddleManager` 正在為這些 segment 提供服務,並將重寫的子查詢傳送給每個程序。`Historical` / `MiddleManager` 程序將接受查詢,對其進行處理並返回結果。`Broker`接收結果並將它們合併在一起以得到最終答案,並將其返回給客戶端。 `Broker`會分析每個請求,優化查詢,儘可能的減少每個查詢必須掃描的資料量。相比於 Broker 過濾器做的優化,每個 segment 內的索引結構允許 Druid 在檢視任何資料行之前先找出哪些行(如果有)與過濾器集匹配。一旦 Druid 知道哪些行與特定查詢匹配,它就只會訪問該查詢所需的特定列。在這些列中,Druid 可以在行與行之間跳過,從而避免讀取與查詢過濾器不匹配的資料。 因此,Druid 使用三種不同的技術來優化查詢效能: 1. 檢索每個查詢需訪問的 segment。 2. 在每個 segment 中,使用索引來標識查詢的行。 3. 在每個 segment 中,僅讀取與特定查詢相關的行和列。 ## 其他系列文章連結 [時間序列資料庫(TSDB)初識與選擇](https://mp.weixin.qq.com/s/9ckUy3Lz9GHTNPauNlpV0w) [十分鐘瞭解 Apache Druid](https://mp.weixin.qq.com/s/dGBfQdmD7niW32BXWb2B0g) > 想了解更多資料儲存,時間序列,Druid 的知識,可關注我的公眾號。點「在看」是我們創造好文的動力 ![公眾號 MageByte](https://magebyte.oss-cn-shenzhen.aliyuncs.com/wechat/qrcode_for_gh_8a8593eb7cb4_258.jp