Druid架構(gòu)設(shè)計(jì)


Druid的架構(gòu)設(shè)計(jì)是對云友好和易維護(hù)的多處理分布式架構(gòu)。架構(gòu)在集群中有最大的靈活性,可以配置和獨(dú)立擴(kuò)展每一個Druid的節(jié)點(diǎn)類型。這樣的架構(gòu)設(shè)計(jì)也提供了更加強(qiáng)的容錯性。一個節(jié)點(diǎn)的宕機(jī)不會立刻影響到另一個節(jié)點(diǎn)。


節(jié)點(diǎn)和服務(wù)器

Druid節(jié)點(diǎn)類型簡介:

  • Coordinator節(jié)點(diǎn):管理集群的元數(shù)據(jù)。
  • Overlord節(jié)點(diǎn):控制數(shù)據(jù)的鑷取。
  • Broker 節(jié)點(diǎn):處理外部客戶端的查詢。
  • Router節(jié)點(diǎn):處理Coordinator、Overlord、Broker上的路由選擇。
  • Historical節(jié)點(diǎn):存儲查詢表的數(shù)據(jù)。
  • MiddleManager節(jié)點(diǎn):負(fù)責(zé)鑷取數(shù)據(jù)。

Druid節(jié)點(diǎn)可以隨意部署,但是為了簡化部署,建議把上述6中節(jié)點(diǎn)部署成3類型服務(wù)器。

  • Master:包括Coordinator和Overlord。管理元數(shù)據(jù)和管理數(shù)據(jù)鑷取。
  • Query:包括Broker和Router。管理外部客戶端的查詢請求。
  • Data:包括Historical和MiddleManager。存儲數(shù)據(jù)和執(zhí)行鑷取數(shù)據(jù)任務(wù)。

外部依賴

除了內(nèi)置的節(jié)點(diǎn)類型,Druid還有3中外部的依賴節(jié)點(diǎn)類型。

深度存儲節(jié)點(diǎn)

每一個Druid服務(wù)器可以訪問共享的文件存儲。在集群部署中,共享文件存儲通常是分布式對象存儲,例如S3、HDFS或者網(wǎng)絡(luò)文件系統(tǒng)。在單節(jié)點(diǎn)部署,通常存儲在本地磁盤。Druid使用深度存儲存儲所有鑷取進(jìn)入系統(tǒng)數(shù)據(jù)。
Druid的深度存儲只能作為你數(shù)據(jù)的備份并在后臺的節(jié)點(diǎn)間傳輸數(shù)據(jù)的方式。
查詢時Historical不會從深度存儲讀取數(shù)據(jù),而是在查詢之前而是讀取本地磁盤的預(yù)取的數(shù)據(jù)塊(segments)。這意味著在查詢數(shù)據(jù)時,Druid沒有必要訪問深度存儲,從而盡可能的最大化的減少了查詢延遲。這要求Druid必須在深度存儲和Historical節(jié)點(diǎn)都有計(jì)劃加載的磁盤空間。
深度存儲是Druid彈性、容錯設(shè)計(jì)非常重要的部分。即使任何一個單獨(dú)的服務(wù)器宕機(jī)和重新配置,Druid可以從深度存儲中引導(dǎo)恢復(fù)。

元數(shù)據(jù)存儲

元數(shù)據(jù)存儲存儲了各種共享系統(tǒng)的元數(shù)據(jù),例如塊數(shù)據(jù)(segment)的可用性信息和任務(wù)信息。在集群部署中,元數(shù)據(jù)通常使用傳統(tǒng)的關(guān)系型數(shù)據(jù)庫存儲,例如PostgreSQL 、Mysql。在單服務(wù)器部署時,元數(shù)據(jù)使用Derby存儲。

Zookeeper

用于互聯(lián)網(wǎng)服務(wù)發(fā)現(xiàn),服務(wù)協(xié)調(diào),主服務(wù)選舉。


架構(gòu)

下圖展示了在推薦的Master節(jié)點(diǎn)、Query節(jié)點(diǎn)、數(shù)據(jù)節(jié)點(diǎn)三種節(jié)點(diǎn)的部署情況下查詢和數(shù)據(jù)流在架構(gòu)之間的情況。


Druid架構(gòu)

存儲設(shè)計(jì)

數(shù)據(jù)源和數(shù)據(jù)段(segments)

Druid數(shù)據(jù)存儲在數(shù)據(jù)源中,數(shù)據(jù)源類似于傳統(tǒng)關(guān)系數(shù)據(jù)庫中的表。每一個數(shù)據(jù)源被時間分割,也可以選擇被其他的屬性值分割。每一個時間范圍是一個數(shù)據(jù)塊(chunk)(例如,時間范圍是一天,數(shù)據(jù)源會一天一個分片)。一個數(shù)據(jù)塊(chunk)被分割成一個或多個數(shù)據(jù)段(segments)。每一個數(shù)據(jù)段(segment)是一個文件,通常包括幾百萬行數(shù)據(jù)。幾個數(shù)據(jù)段組成數(shù)據(jù)塊,數(shù)據(jù)塊在時間線上如下圖所示:


數(shù)據(jù)塊

一個數(shù)據(jù)源可能由幾個數(shù)據(jù)段組成,也有可能是上千或者上百萬個數(shù)據(jù)段組成。MiddleManager創(chuàng)建每一個數(shù)據(jù)段,在創(chuàng)建的時候數(shù)據(jù)段是易變的,沒有提交的。數(shù)據(jù)段創(chuàng)建的數(shù)據(jù)文件是被壓縮的而且可以支持快速查詢,數(shù)據(jù)段的創(chuàng)建過程包含如下幾個步驟:

  • 轉(zhuǎn)換成列式存儲
  • bitMap索引
  • 多樣性壓縮算法
    • 對文本列字典編碼成id最小化存儲
    • bitMap索引進(jìn)行bitMap壓縮
    • 對所有的列進(jìn)行類型感知的壓縮
      數(shù)據(jù)段會定期的提交和發(fā)布。在這時,數(shù)據(jù)段會存儲到深度存儲,然后數(shù)據(jù)段會不可變,從MiddleManagers轉(zhuǎn)移到Historical,數(shù)據(jù)段的入口信息會記錄在元數(shù)據(jù)存儲中。數(shù)據(jù)段的入口信息是自描述位源數(shù)據(jù),包括數(shù)據(jù)塊的模式、大小、在深度存儲的位置。Coordinator利用數(shù)據(jù)塊的入口信息知道數(shù)據(jù)在集群是否可用。

索引

通過索引機(jī)制來創(chuàng)建新數(shù)據(jù)段,通過handoff機(jī)制來發(fā)布數(shù)據(jù)塊和在Historical開始服務(wù)。機(jī)制如下:
1、索引任務(wù)開始運(yùn)行和創(chuàng)建一個新的數(shù)據(jù)段。任務(wù)在開始創(chuàng)建數(shù)據(jù)段之前需要確定數(shù)據(jù)段的標(biāo)識符。對于追加索引任務(wù)(例如Kafka任務(wù)或者追加模式的索引任務(wù))然后Overlord會收集數(shù)據(jù)和默認(rèn)會把新的數(shù)據(jù)分區(qū)加入已經(jīng)存在的數(shù)據(jù)段中。對于覆蓋的索引任務(wù)(例如hadoop任務(wù),非追加模式的索引任務(wù))會鎖住一段時間范圍,然后創(chuàng)建一個新版本的數(shù)據(jù)段和一系列新數(shù)據(jù)段。
2、如果索引任務(wù)是一個實(shí)時任務(wù)(例如Kafka任務(wù)),這個時候的數(shù)據(jù)段是可以立刻查詢到,可用的,但是還沒有發(fā)布。
3、當(dāng)索引任務(wù)結(jié)束從數(shù)據(jù)段讀取數(shù)據(jù),這個數(shù)據(jù)段會存儲到深度存儲,然后發(fā)布這個數(shù)據(jù)段,把數(shù)據(jù)段的相關(guān)信息存儲到元數(shù)據(jù)。
4、如果索引任務(wù)是一個實(shí)時任務(wù),會從Historical加載數(shù)據(jù)段。如果不是實(shí)時任務(wù),索引任務(wù)已經(jīng)存在。

Coordinator / Historical上的機(jī)制:
1、Coordinator定期把新發(fā)布的數(shù)據(jù)段(segments)提交到元數(shù)據(jù)存儲。(默認(rèn)一分鐘提交一次)
2、當(dāng)Coordinator發(fā)現(xiàn)已經(jīng)發(fā)布、使用過但是不可用的數(shù)據(jù)段,Coordinator節(jié)點(diǎn)會指派Historical加載這些數(shù)據(jù)段。
3、Historical加載上述數(shù)據(jù)段,然后這些數(shù)據(jù)段開始服務(wù)。
4、此時索引服務(wù)開始切換索引。

Segment標(biāo)識符

Segment標(biāo)識符由下面四個部分組成:

  • 數(shù)據(jù)源名字。
  • 時間區(qū)間。數(shù)據(jù)段(segment)有對應(yīng)的時間塊時間,在鑷取數(shù)據(jù)的時候會指定數(shù)據(jù)段粒度相對應(yīng)的時間區(qū)間。
  • 版本號。版本號一般是數(shù)據(jù)段第一次創(chuàng)建的時候的ISO8601時間戳。
  • 分區(qū)標(biāo)號。分區(qū)標(biāo)號是一個int類型,和數(shù)據(jù)源名字、時間區(qū)間、版本號組合在一起是唯一的,但是沒有必要是連續(xù)的。

例如:一個數(shù)據(jù)段的數(shù)據(jù)源是clarity-cloud0,時間塊是2018-05-21T16:00:00.000Z/2018-05-21T17:00:00.000Z,版本是2018-05-21T15:56:09.909Z,分區(qū)標(biāo)號是1,因此此數(shù)據(jù)段的標(biāo)識符如下:

clarity-cloud0_2018-05-21T16:00:00.000Z_2018-05-21T17:00:00.000Z_2018-05-21T15:56:09.909Z_1

如果數(shù)據(jù)段的分區(qū)標(biāo)號是0,那么數(shù)據(jù)標(biāo)識符可以忽略分區(qū)標(biāo)號。數(shù)據(jù)塊的數(shù)據(jù)段編號是從0開始。例如跟上述同一個數(shù)據(jù)塊中分區(qū)編號為0的數(shù)據(jù)段的標(biāo)識符如下:

clarity-cloud0_2018-05-21T16:00:00.000Z_2018-05-21T17:00:00.000Z_2018-05-21T15:56:09.909Z

數(shù)據(jù)段(Segment)的版本

數(shù)據(jù)段的版本是為了支持批量模式的覆蓋。如果你只是追加數(shù)據(jù),那么每一個數(shù)據(jù)塊只有一個版本。但是當(dāng)出現(xiàn)一個同一個數(shù)據(jù)源同一個時間區(qū)間間隔時,高版本號的數(shù)據(jù)會覆蓋低版本的數(shù)據(jù),這個時候老版本的數(shù)據(jù)會從集群移除。
新老版本的數(shù)據(jù)切換對用戶來說瞬間的。Druid開始加載新版本的數(shù)據(jù)段之前這部分?jǐn)?shù)據(jù)是查詢不到的,等數(shù)據(jù)完全加載完成之后,查詢使用的數(shù)據(jù)瞬間切換到新版本數(shù)據(jù)段,然后花幾分鐘刪除老版本的數(shù)據(jù)。

數(shù)據(jù)段(Segment)的生命周期

數(shù)據(jù)段(Segment)的生命周期涉及到如下三個方面:
1、元數(shù)據(jù):當(dāng)一個數(shù)據(jù)段創(chuàng)建完成的時候數(shù)據(jù)段元數(shù)據(jù)會存儲到元數(shù)據(jù)存儲器中。元數(shù)據(jù)是一個及kb的json數(shù)據(jù)。數(shù)據(jù)段的元數(shù)據(jù)存儲到元數(shù)據(jù)存儲器這個過程稱作發(fā)布。數(shù)據(jù)段的元數(shù)據(jù)信息中有個布爾值的字段used控制數(shù)據(jù)段是否可以查詢。實(shí)時任務(wù)創(chuàng)建的數(shù)據(jù)段在發(fā)布之前就可以查詢,然而數(shù)據(jù)段完成之后只有發(fā)布了,此數(shù)據(jù)段不會再接受數(shù)據(jù)的追加。
2、深度存儲:數(shù)據(jù)段已經(jīng)構(gòu)造完成,數(shù)據(jù)段的數(shù)據(jù)文件會發(fā)送到深度存儲,然后數(shù)據(jù)塊發(fā)布元數(shù)據(jù)到元數(shù)據(jù)存儲。
3、可查詢性:數(shù)據(jù)塊的查詢可用性存在于實(shí)時任務(wù)節(jié)點(diǎn)和Historical節(jié)點(diǎn)。

你可以通過Druid SQL的sys.segment這張表來查看當(dāng)前活躍的數(shù)據(jù)段。

  • is_published:當(dāng)數(shù)據(jù)段的元數(shù)據(jù)已經(jīng)發(fā)布到元數(shù)據(jù)存儲且usedtrue時時,此字段為true
  • is_available:當(dāng)數(shù)據(jù)段在實(shí)時節(jié)點(diǎn)或Historical節(jié)點(diǎn)可以查詢時,此字段值為true。
  • is_realtime:當(dāng)數(shù)據(jù)段只在實(shí)時節(jié)點(diǎn)可以用是值為true。當(dāng)數(shù)據(jù)源在實(shí)時鑷取數(shù)據(jù)時,此字段值為true;當(dāng)此數(shù)據(jù)段發(fā)布之后并切換源數(shù)據(jù)之后,值會變成false。
  • is_overshadown:當(dāng)數(shù)據(jù)段已經(jīng)發(fā)布并且完全被其他的已經(jīng)發(fā)布的數(shù)據(jù)段覆蓋時,值為true。當(dāng)數(shù)據(jù)源在實(shí)時鑷取數(shù)據(jù)時,此字段值為true;通常這是一個臨時的狀態(tài),在此狀態(tài)下數(shù)據(jù)段的used標(biāo)志會自動的設(shè)置為false。

查詢

查詢需求首先發(fā)送到Broker,然后Broker會識別出查詢需求需要用到數(shù)據(jù)段。識別數(shù)據(jù)段的方法是通過刪除數(shù)據(jù)源上不相關(guān)的時間區(qū)間的數(shù)據(jù)段或者刪除數(shù)據(jù)源上不相關(guān)的屬性的數(shù)據(jù)段,這取決于數(shù)據(jù)源分割方式。Broker會識別出這些數(shù)據(jù)段分別在Historical和MiddlerManager上哪些節(jié)點(diǎn)上,并把子查詢發(fā)送到數(shù)據(jù)段每一個節(jié)點(diǎn)。Historical/MiddlerManager會接受查詢請求并執(zhí)行查詢,把結(jié)果返回。Broker接到查詢結(jié)果,然后把查詢結(jié)果組合成最后的結(jié)果,最后把結(jié)果發(fā)送給最初的查詢客戶端。
Broker的數(shù)據(jù)段剪枝是限制查詢時掃描數(shù)據(jù)數(shù)量的重要方法,但是不是唯一方法。更小粒度水平過濾器的的剪枝效果比上面的Broker剪枝效果更好,因?yàn)樵诓樵冎皵?shù)據(jù)段里面的索引結(jié)構(gòu)可以讓Druid找出過濾數(shù)據(jù)。當(dāng)Druid知道查詢需要用到哪些行,Druid只需要訪問這些需要的的行的列就可以了。
Druid使用三種不同技術(shù)最大化提高查詢性能:

  • 每一個查詢只訪問剪枝后的數(shù)據(jù)段。
  • 在數(shù)據(jù)塊中使用索引識別出需要訪問的行。
  • 在數(shù)據(jù)塊中只讀查詢相關(guān)的行和列。

翻譯:https://druid.apache.org/docs/latest/design/architecture.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 整體架構(gòu) Druid集群是由一組扮演不同角色的,功能不同的節(jié)點(diǎn)組成的,我們先從這幅圖介紹一下幾類節(jié)點(diǎn),以及它們之間...
    MeazZa閱讀 524評論 0 1
  • Druid.io(以下簡稱Druid)是面向海量數(shù)據(jù)的、用于實(shí)時查詢與分析的OLAP存儲系統(tǒng)。Druid的四大關(guān)鍵...
    大詩兄_zl閱讀 6,550評論 0 9
  • 我們知道Druid能夠同時提供對大數(shù)據(jù)集的實(shí)時攝入和高效復(fù)雜查詢的性能,主要原因就是它獨(dú)到的架構(gòu)設(shè)計(jì)和基于Data...
    零度沸騰_yjz閱讀 21,837評論 3 17
  • 我們知道Druid能夠同時提供對大數(shù)據(jù)集的實(shí)時攝入和高效復(fù)雜查詢的性能,主要原因就是它獨(dú)到的架構(gòu)設(shè)計(jì)和基于Data...
    allin8116閱讀 522評論 0 2
  • 我寫那么多拙劣的文字不過是自娛自樂罷了。
    泰平閱讀 152評論 0 0

友情鏈接更多精彩內(nèi)容