Druid:實時分析資料儲存

banq發表於2022-12-04

Apache Druid是一個開源資料庫,專為低延遲的近實時和歷史資料分析而設計,Druid 被NetflixConfluentLyft等公司用於各種不同的用例。

這個領域有Clickhouse、trino、kylin、bigquery、snowflake、Apache doris等很多競爭對手,但Druid 的速度驚人地快。

Druid 支援近實時和歷史訪問模式的目標使其獨一無二,近乎實時的攝取允許像基於日誌的生產警報(類似於Netflix的使用案例)這樣的應用快速找到問題,同時也針對大量的歷史資料進行執行。
相比之下,許多資料倉儲產品是在重複的 "批處理 "基礎上進行更新的,在指標被記錄的時間和它們可用於分析的時間之間引入了滯後。

關鍵概念

1、分段Segments和資料來源data source
分段是Druid的一個關鍵抽象:它們是一個不可變的(但有版本的)資料結構,儲存著單個記錄的集合。
分段的集合被組合成資料來源,即Druid版本的資料庫表。
每個分段都儲存了在給定時間段內到達的所有記錄,用於指定的資料來源。

Druid部署在兩種資料來源中儲存狀態:

  1. MySQL,它包含配置和後設資料,如現有網段的索引。
  2. Zookeeper,它儲存了系統的當前狀態(包括段的多個副本在系統中的機器上的分佈情況)。


2、儲存格式
如前所述,Druid的一個關鍵抽象是分段,一個用於儲存資料的不可變的資料結構。每個段都與一個資料來源(Druid對傳統表格的概念)相關聯,幷包含特定時間段的資料。

儲存在段中的資料由兩種型別組成:維度和度量。維度是行聚合或過濾的值,而度量對應於數字資料(如計數)。

分段還包含一個版本號。如果一個段被改變了,版本號會被增加,並且段的新版本會被髮布--這可能發生在一個先前被確定的段的延遲事件中。協調人節點透過指示歷史節點獲取新版本並放棄舊版本,來處理向新版本段的遷移。由於這種方法,據說Druid實現了多版本併發控制(MVCC)。這篇論文評論沒有詳細介紹MVCC,但是關於這個講座中的一些想法有很好的資源。一個關鍵的想法是,資料有多個有效的版本(如快照),不同的讀者可以檢視一個資料集的不同版本。.

重要的是,分段以列而不是行來儲存資料--這種方法被稱為 "列式儲存"。這種設計被用於其他一些資料庫(如Redshift和Cassandra)和檔案格式(如Parquet),因為它提供了效能優勢。

例如,如果一個查詢是選擇一個列的子集,資料庫只需要查詢這些列的資料子集。基於行的解決方案將掃描每一行,選擇出相關的列。雖然這兩種掃描都會產生相同的結果,但基於行的掃描(幾乎)保證會不必要地訪問那些不需要回答查詢的列,也不會出現在查詢結果中。


架構
Druid透過攝取資料建立分段,然後在針對資料來源的查詢響應時訪問這些分段。
Druid架構使用了四種型別的節點,較新版本的系統似乎打破了實現攝取資料和響應查詢的功能TODO:

  • 實時節點、
  • 歷史節點、
  • 經紀人節點
  • 協調者節點。


實時節點
實時節點有兩個責任:從生產者那裡攝取資料,以及實現使用者對最近資料的請求的響應。

生產者向實時節點提供原始資料(如資料庫中的行),或經過轉換的資料(如流處理管道的輸出)--一個常見的生產者模式依賴於Kafka主題。Kafka(或其他訊息匯流排方法)有助於攝取的可用性和可擴充套件性--實時節點可以將它們所消耗的偏移量儲存到流中,如果它們崩潰/重啟,則重置為該偏移量。為了擴充套件攝取,多個實時節點可以讀取同一訊息匯流排的不同子集。

當一個實時節點從生產者那裡消耗記錄時,它會檢查與記錄相關的時間段和資料來源,然後將傳入的記錄路由到具有相同(時間段、資料來源)鍵的記憶體緩衝器。

除了攝取之外,每個實時節點對訪問最近資料的查詢作出回應。為了響應這些請求,各節點使用臨時的記憶體索引進行掃描。

歷史節點
歷史節點從儲存中讀取不可變的分段,並對訪問這些段的查詢作出響應--協調者節點(在下一節中討論)控制歷史節點獲取哪些段。
當一個歷史節點成功下載一個分段時,它會向系統的服務發現元件(Zookeeper)宣佈這一事實,允許使用者查詢訪問該片分段。
不幸的是,如果Zookeeper離線,系統將無法提供新的分段--歷史節點將無法宣佈成功獲取片段,因此Druid中負責查詢資料的元件將無法轉發查詢。

使用不可變分段的決定簡化了歷史節點的實現:

  • 首先,它簡化了系統的擴充套件--如果有許多請求涵蓋一個段,更多的歷史節點可以儲存該段的副本,導致查詢分散在叢集中。
  • 其次,在段上操作,而不是在較低層次的抽象上操作,意味著歷史節點可以簡單地等待被告知有一個新的資料版本需要提供服務,而不是需要傾聽段本身的變化。


協調節點
協調節點配置哪些片段被儲存在歷史節點上一個片段的多個副本可以儲存在叢集中的不同歷史節點上,以擴大查詢範圍並增加冗餘度。從閱讀Druid文件來看,似乎有一個新的、獨立的節點型別負責控制資料消化,稱為 "Overlord霸王"。

為了做出決定,協調者節點從兩個地方讀取資料:MySQL和Zookeeper。

  • MySQL持久地儲存關於段的宇宙的資訊本質上是儲存(時間段、資料來源、版本)--雖然一個段可以有多個副本,但在MySQL資料庫中會有一個條目來代表它的型別,以及關於每個段型別的相關後設資料,比如一個具有特定配置的段應該在歷史節點上保留多長時間。
  • Zookeeper儲存了系統提供的所有網段的當前狀態--實時節點和歷史節點使用它來宣佈哪些網段可用的變化。協調人節點也會對段進行負載平衡。在Druid文件中對平衡段的負載進行了更詳細的討論。.


論文中提到,叢集中有多個正在執行的協調者節點,但每次只有一個 "領導者"--其他節點用於故障轉移。為了擴充套件協調功能,聽起來有可能建立多組協調者節點,每個節點負責資料集的一個分割槽,儘管我在論文中沒有看到這方面的討論。. 如果協調者節點變得不可用(無論是由於MySQL或Zookeeper問題),歷史和實時節點將繼續執行,但可能會變得過載(由於不執行負載平衡功能)。此外,該檔案指出,這種故障模式導致新的資料變得不可用。

經紀人節點
最後,Broker節點接收來自外部客戶的請求,從Zookeeper讀取狀態,並根據情況將請求轉發給歷史和實時節點的組合。經紀人節點也可以在本地快取段,以限制未來訪問相同資料的查詢的出站段請求的數量。

如果Zookeeper變得不可用,那麼經紀商就會使用他們的 "最後已知良好狀態 "來轉發查詢。


結論
Druid是 "Lambda架構 "的最早實現之一,其中資料是由批處理和流式系統組合提供的。最近的 "Kappa "和 "Delta "架構的方法,特別是Databricks的Delta Lake,似乎是Druid最初提議的演變。


網友回應:
1、我們在工作中大規模使用 Druid,而且它實際上不需要太多維護。事實上,在大多數情況下,除了我們自己的錯誤配置導致的一些事件之外,它會嗡嗡作響。在 Kubernetes 上執行。最煩人的事情是調整段壓縮。

2、從我見過的幾個嘗試使用 Druid 的專案中,我的感覺是大規模管理叢集需要大量的基礎架構開銷/DevOps 支援,並且需要相當複雜的攝取管道才能正確載入資料格式。
有趣的是,我聽說從這個角度來看,ClickHouse 更容易部署,具有類似的效能,但我很樂意讓其他人對這些和類似的資料儲存有看法/經驗。

3、與其競爭對手Clickhouse 和 Pinot相比,設定 Druid 叢集是最簡單的。
特別是因為攝取直接進入 S3。我們並不真正擔心備份(只處理 PG 備份)。
只要確保你的 ZK 快樂,一切都會好起來的。
Druid 的難點在於調整:
- 攝取:規範定義、壓縮、分片策略、RAM 消耗等。
- 和查詢效能:RAM 消耗、執行緒數、超時等。

 

相關文章