文章目錄
Druid資料結構及架構原理
一、Druid資料結構
二、Druid架構原理
1、四類節點
2、三個外部依賴
3、資料寫入及讀取原理
Druid資料結構及架構原理
一、Druid資料結構
Druid中的資料存儲在datasource中,類似RDBMS中的table,每個datasource中按照時間劃分,每個時間範圍稱為一個chunk(一般一天為一個chunk),在一個chunk中資料根據次元的Hash或者範圍被分成一個或者多個segment,每個segment都是一個單獨的檔案,通常包含幾百萬行資料,這些segment是按照時間組織成的,是以在按照時間查詢資料時,效率非常高。實際上,datasource和chunk都是抽象的,Druid底層存儲就是Segment,一旦一個Segment生成後就無法被修改,隻能通過生成一個新的Segment來代替舊版本的Segment。
Segment内部采用列式存儲,并不是每個列都對應一個獨立的檔案,而是每列都有獨立的資料結構,這些列存儲在一個檔案中。
在Segment中資料類型有三種:時間戳、次元列、名額列,舉例如下:
對于時間戳和名額列,實際存儲是一個數組。對于次元列而言,由于需要支援filter和group by操作,是以Druid使用了字典編碼(Dictionary Encoding)和位圖索引(Bitmap Index)來存儲每個次元列。每個次元列需要三個資料結構:
- 需要一個字典資料結構,将次元值映射成一個整數ID
- 使用上面的字典編碼,将該列所有維值放在一個清單中。
- 對于列中不同的值,使用bitmap資料結構辨別哪些行包含這些值。
例如,有如下表資料:
時間戳 | 次元列 | 名額列 | |
dt(時間) | loc(位置) | item(物品) | amount(金額) |
2022-07-01 | 北京 | 書籍 | 100 |
2022-07-01 | 北京 | 電腦 | 200 |
2022-07-01 | 上海 | 電腦 | 300 |
2022-07-01 | 廣州 | 手機 | 400 |
2022-07-01 | 杭州 | 水果 | 500 |
2022-07-01 | 北京 | 書籍 | 600 |
Druid将以上資料存儲建構的位圖索引如下,來實作資料快速查找:
- 将次元列中的值映射成一個個整數ID
次元列有loc,item兩列,其中的不重複值有:北京、上海、廣州、杭州、書籍、電腦、手機、水果,假設映射後的整數ID組成的字典編碼如下:
北京-0,上海-1,廣州-2,杭州-3,書籍-4,電腦-5,手機-6,水果-7
- 建構的位圖索引如下
原始列值 key | 列值對應字典編碼value | bitmap 位圖 | |
北京 | 1 | 1 | 1 |
上海 | 1 | 1 | |
廣州 | 2 | 1 | |
杭州 | 3 | 1 | |
書籍 | 4 | 1 | 1 |
電腦 | 5 | 1 | 1 |
手機 | 6 | 1 | |
水果 | 7 | 1 |
我們要過濾找到“北京”并且“電腦”的資料,那麼隻需要在位圖索引中找到北京對應的行和廣州對應的行做與運算即可。假設根據上表資料我們查詢sql如下:
select sum(amount) as totalamount
from tbl
where loc = “北京”and “item”=“電腦”
那麼根據以上位圖,我們可以看到條件“loc=北京”對應的bitmap位圖為(110001),”item=電腦”對應的位圖為(011000),查詢條件就是(110001) and(011000)結果就是找(010000)所對應的行,也就是找出第2行資料即可。
同理,如果要按照“loc”和”“item”分組,隻需要找到“loc”下各個值與“item”下各個值進行與運算即可。
Segment命名可以讓我們在大量的Segment檔案中快速找到我們查詢的Segment檔案,Segment命名包含四個部分:資料源(DataSource)、時間間隔(包含開始時間和結束時間兩部分)、版本号和分區(當一個Chunk中有多個Segment時會有分區号)。
例如:
kafkadata_2022-07-30T00:00:00.000Z_2022-07-31T00:00:00.000Z_2022-08-02T12:02:03.456Z_1
- kafkadata : DataSource名稱。
- 2022-07-30T00:00:00.000Z:開始時間,該Segment存儲最早的資料。
- 2022-07-31T00:00:00.000Z:結束時間,該Segment存儲最晚的資料。
- 2022-08-02T12:02:03.456Z:版本号,該Segment啟動時間,由于Druid支援批量覆寫操作,當批量攝入與之前相同資料源,相同時間間隔資料時,資料就會被覆寫,這時候版本号就會被更新。在Druid中,如果隻是追加資料,那麼每個時間chunk隻有一個版本,如果覆寫資料時,Druid會加載全部新資料生成一個新的版本号,然後會删除舊的Segment。
- 1:分區号,如果分區号為0,會省略,分區的表現其實就是分目錄。
注意:單機運作Druid,Druid生成的Segment都在$DRUID_HOME/var/druid/segment目錄下。
二、Druid架構原理
下圖是Druid的架構圖,藍色代表Druid服務,黃色代表Druid的程序,每個程序所在的節點我們也可以稱為目前程序節點,例如:Borker程序所在節點,可以稱為該節點為Broker節點。整體來看Druid可以分為四類節點和三個依賴。
1、四類節點
1.1、實時節點(RealTime Node)
實時類節點包含很多程序角色,也可以稱為很多,為了防止單點故障,是以這些角色沒有在一台節點啟動,實時類節點包含的程序如下:
- Overlord(統治程序)
該程序監視MiddleManager程序,并且是資料攝入Druid的控制器,負責将提取任務配置設定給MiddleManagers并協調Segement釋出。類似Yarn中的ResourceManager,負責叢集資源的管理和配置設定。
- MiddleManager(中間管理程序)
類似Yarn中NodeManager,負責單個節點的資源管理和配置設定。該程序負責接收實時資料和批資料,生成Segment資料檔案。
- Router
該程序可以将請求路由到Broker、Coordinator、Overlord。
1.2、協調節點(Coodinator Node)
- Coordinator(協調程序)
主要負責Historical的資料負載均衡,以及通過規則(Rule)管理資料的生命周期。預設每隔1分鐘同步中繼資料庫,感覺新生成的Segment,将待加載的Segment資訊儲存在Zookeeper目錄中(此目錄是對應線上的Historical Node在Zookeeper中的目錄),Historical Node感覺到需要加載新的Segment時,首先去本地磁盤目錄下檢查該Segment是否已下載下傳,如果沒有,會從zookeeper中擷取對應的中繼資料(該Segment存儲在何處,如果解壓等)擷取該檔案并加載到記憶體中,同時在zookeeper對應目錄下标記聲明該Segment已被加載,進而該Segment可以被查詢。
協調程序除了告訴Historical加載新資料之外,還會負責協調解除安裝過期資料、複制資料、和為了負載均衡移動資料。
如果叢集内所有的Coordinator Node都停止服務,整個叢集對外依然有效,不過新Segment不會被加載,過期的Segment也不會被丢棄,即整個叢集内的資料拓撲會一直保持不變,直到新的Coordinator Node服務上線。
1.3、曆史節點(Historical Node)
- Historical(曆史程序)
該程序負責存儲已生成好的Segment資料檔案,以供資料查詢。當收到Coordinator程序通知的時候,檢查本地緩存中已經存在的Segment資料檔案,然後從DeepStorage中下載下傳其他不在本地的Segment資料檔案加載到記憶體提供查詢。Historical程序是整個叢集查詢性能的核心所在,承擔大部分的Segment查詢。
1.4、查詢節點(Broker Node)
- Borker(查詢程序)
該程序負責用戶端資料的查詢,并将這些查詢轉發給Historical和middleManager。
Druid程序可以以任意方式進行部署,為了友善部署,建議分為三種伺服器類型:主伺服器(Master)、查詢伺服器(Query)、資料伺服器(Data)。
- Master:運作Coordinator和Overlord程序,負責叢集可用和讀取資料。
- Query:運作Broker和Router程序,負責處理外部用戶端的查詢。
- Data:運作Historical和Middle Manager程序,負責資料接收和所有可查詢資料的存儲。
2、三個外部依賴
2.1、Metadata Storage
中繼資料存儲,存儲Druid叢集的中繼資料資訊,比如:Segment的相關資訊,一般用MySQL或者PostgreSQL。
2.2、Zookeeper
為Druid叢集提供協調服務,例如:
- Broker Node查詢節點通過Zookeeper來感覺實時節點和曆史節點的存在,提供查詢服務。
- 協調節點通過zookeeper感覺曆史節點,實作負載均衡。
- Overlords 統治節點、Coordinators協調節點的Leader的選舉。
2.3、Deep Storage
資料檔案存儲,存放生成的Segment資料檔案,并供Historical節點進行下載下傳,對于單節點叢集可以使本地磁盤,對于分布式叢集一般是HDFS,也可以是NFS挂載磁盤、S3等。
3、資料寫入及讀取原理
- 📢歡迎點贊 👍 收藏 ⭐留言 📝 如有錯誤敬請指正!
- 📢本文由 Lansonli 原創
- 📢停下休息的時候不要忘了别人還在奔跑,希望大家抓緊時間學習,全力奔赴更美好的生活✨