掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
Druid是一個(gè)快速的列式分布式的支持實(shí)時(shí)分析的數(shù)據(jù)存儲(chǔ)系統(tǒng)。它在處理PB級(jí)數(shù)據(jù)、毫秒級(jí)查詢、數(shù)據(jù)實(shí)時(shí)處理方面,比傳統(tǒng)的OLAP系統(tǒng)有了顯著的性能改進(jìn)。

10年積累的成都做網(wǎng)站、成都網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問(wèn)題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有雁峰免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
OLAP分析分為關(guān)系型聯(lián)機(jī)分析處理(ROLAP)、多維聯(lián)機(jī)分析處理(MOLAP)兩種,MOLAP需要數(shù)據(jù)預(yù)計(jì)算好為一個(gè)多維數(shù)組,典型方式就是Cube,而ROLAP就是數(shù)據(jù)本身什么樣就是什么樣,查詢時(shí)通過(guò)MPP提高分布式計(jì)算能力。
Druid是ROLAP路線,實(shí)時(shí)攝取數(shù)據(jù),實(shí)時(shí)出結(jié)果,不像Kylin一樣,有一個(gè)顯式的預(yù)計(jì)算過(guò)程。
MPP:俗稱大規(guī)模并行處理,數(shù)據(jù)庫(kù)集群中,每個(gè)節(jié)點(diǎn)都有獨(dú)立的磁盤存儲(chǔ)系統(tǒng)跟內(nèi)存系統(tǒng),業(yè)務(wù)數(shù)據(jù)根據(jù)數(shù)據(jù)庫(kù)模型跟應(yīng)用特點(diǎn)被劃分到各個(gè)節(jié)點(diǎn),MPP就是將任務(wù)并行分散到多個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)計(jì)算完畢后將結(jié)果匯總下來(lái)得到最終結(jié)果。
Lambda架構(gòu):該 架構(gòu)的設(shè)計(jì)是為了在處理大規(guī)模數(shù)據(jù)時(shí),同時(shí)發(fā)揮流處理和批處理的優(yōu)勢(shì)。通過(guò)批處理提供全面、準(zhǔn)確的數(shù)據(jù),通過(guò)流處理提供低延遲的數(shù)據(jù),從而達(dá)到平衡延遲、吞吐量和容錯(cuò)性的目的。為了滿足下游的即席查詢,批處理和流處理的結(jié)果會(huì)進(jìn)行合并。一般有三層。
Batch Layer:批處理層,對(duì)離線的歷史數(shù)據(jù)進(jìn)行預(yù)計(jì)算。
Speed Layer:加速處理層,處理實(shí)時(shí)的增量數(shù)據(jù)。
Serving Layer:合并層,計(jì)算歷史數(shù)據(jù)和實(shí)時(shí)數(shù)據(jù)都有了。
注意:阿里巴巴也曾創(chuàng)建過(guò)一個(gè)開(kāi)源項(xiàng)目叫作Druid(簡(jiǎn)稱阿里Druid),它是一個(gè)數(shù)據(jù)庫(kù)連接池的項(xiàng)目。阿里Druid和本文討論的Druid沒(méi)有任何關(guān)系,它們解決完全不同的問(wèn)題。
?句話總結(jié),Druid適合帶時(shí)間維度、海量數(shù)據(jù)的實(shí)時(shí)/準(zhǔn)實(shí)時(shí)分析
產(chǎn)品對(duì)比
Druid為了實(shí)現(xiàn)海量數(shù)據(jù)實(shí)時(shí)分析采?了?些特殊的?段和?較復(fù)雜的架構(gòu),大致分兩節(jié)分別介紹。
Druid能實(shí)現(xiàn)海量數(shù)據(jù)實(shí)時(shí)分析,主要采取了如下特殊手段。
分析查詢逃不開(kāi)聚合操作,Druid在數(shù)據(jù)?庫(kù)時(shí)就提前進(jìn)行了聚合,這就是所謂的預(yù)聚合(roll-up)。Druid把數(shù)據(jù)按照選定維度的相同的值進(jìn)行分組聚合,可以?大降低存儲(chǔ)?小。數(shù)據(jù)查詢的時(shí)候只需要預(yù)聚合的數(shù)據(jù)基礎(chǔ)上進(jìn)行輕量的?次過(guò)濾和聚合即可快速拿到分析結(jié)果,當(dāng)然預(yù)聚合是以犧牲明細(xì)數(shù)據(jù)分析查詢?yōu)榇鷥r(jià)。
要做預(yù)聚合,Druid要求數(shù)據(jù)能夠分為三個(gè)部分:
{"timestamp":"2018-01-01T01:01:35Z","srcIP":"1.1.1.1","dstIP":"2.2.2.2","packets":20,"bytes":9024}
{"timestamp":"2018-01-01T01:01:51Z","srcIP":"1.1.1.1","dstIP":"2.2.2.2","packets":255,"bytes":21133}
{"timestamp":"2018-01-01T01:01:59Z","srcIP":"1.1.1.1","dstIP":"2.2.2.2","packets":11,"bytes":5780}
{"timestamp":"2018-01-01T01:02:14Z","srcIP":"1.1.1.1","dstIP":"2.2.2.2","packets":38,"bytes":6289}
{"timestamp":"2018-01-01T01:02:29Z","srcIP":"1.1.1.1","dstIP":"2.2.2.2","packets":377,"bytes":359971}
{"timestamp":"2018-01-01T01:03:29Z","srcIP":"1.1.1.1","dstIP":"2.2.2.2","packets":49,"bytes":10204}
{"timestamp":"2018-01-02T21:33:14Z","srcIP":"7.7.7.7","dstIP":"8.8.8.8","packets":38,"bytes":6289}
{"timestamp":"2018-01-02T21:33:45Z","srcIP":"7.7.7.7","dstIP":"8.8.8.8","packets":123,"bytes":93999}
{"timestamp":"2018-01-02T21:35:45Z","srcIP":"7.7.7.7","dstIP":"8.8.8.8","packets":12,"bytes":2818}比如上面這樣一份明細(xì)數(shù)據(jù),timestamp當(dāng)然是Timestamp列,srcIP和dstIP是Dimension列(維度),packets和bytes是Metric列。該數(shù)據(jù)?庫(kù)到Druid時(shí)如果我們打開(kāi)預(yù)聚合功能(可以不打開(kāi)聚合,數(shù)據(jù)量?大就不?了),要求對(duì)packets和bytes進(jìn)?行行累加(sum),并且要求按條計(jì)數(shù)(count *),聚合之后的數(shù)據(jù)是這樣的:
聚合后數(shù)據(jù)
行式:
行式存儲(chǔ)查詢
列式:
列式存儲(chǔ)查詢
在大數(shù)據(jù)領(lǐng)域列式存儲(chǔ)是個(gè)常見(jiàn)的優(yōu)化手段,一般在OLTP數(shù)據(jù)庫(kù)會(huì)用行式存儲(chǔ),OLAP數(shù)據(jù)庫(kù)會(huì)使用列式存儲(chǔ)。列式存儲(chǔ)一般有如下優(yōu)點(diǎn):
對(duì)于分析查詢,?般只需要?到少量的列,在列式存儲(chǔ)中,只需要讀取所需的數(shù)據(jù)列即可。例例如,如果您需要100列列中的5列,則I / O減少20倍。
按列分開(kāi)存儲(chǔ),按數(shù)據(jù)包讀取時(shí)因此更易于壓縮。列中的數(shù)據(jù)具有相同特征也更易于壓縮, 這樣可以進(jìn)?步減少I / O量。
由于減少了I / O,因此更更多數(shù)據(jù)可以容納在系統(tǒng)緩存中,進(jìn)?步提?分析性能。
Druid的數(shù)據(jù)在存儲(chǔ)層面是按照Datasource和Segments實(shí)現(xiàn)多級(jí)分區(qū)存儲(chǔ)的,并建?了位圖索引。
Segment跟Chunk
Segment是Druid數(shù)據(jù)存儲(chǔ)的最小單元,內(nèi)部采用列式存儲(chǔ),建立了位圖索引,對(duì)數(shù)據(jù)進(jìn)行了編碼跟壓縮。
Druid數(shù)據(jù)存儲(chǔ)的攝取方式、聚合方式、每列數(shù)據(jù)存儲(chǔ)的字節(jié)起始位都有存儲(chǔ)。
假設(shè)現(xiàn)有這樣一份數(shù)據(jù):
原始數(shù)據(jù)
以tp為時(shí)間列,appkey和city為維度,以value為度量值,導(dǎo)?Druid后按天聚合,最終結(jié)果是:
聚合后
數(shù)據(jù)經(jīng)過(guò)聚合之后查詢本身就很快了,為了進(jìn)?步加速對(duì)聚合之后數(shù)據(jù)的查詢,Druid會(huì)建立位圖索引:
位圖索引
上?的位圖索引不是針對(duì)列?是針對(duì)列的值,記錄了列的值在數(shù)據(jù)的哪?行出現(xiàn)過(guò),第一列是具體列的值,后續(xù)列標(biāo)識(shí)該列的值在某??是否出現(xiàn)過(guò),依次是第1列到第n列。例如appkey1在第??出現(xiàn)過(guò),在其他?沒(méi)出現(xiàn),那就是1000(例子中只有四個(gè)列)。
Select sum(value) from xxx where time=’2019-11-11’and appkey in
(‘a(chǎn)ppkey1’,’appkey2’) and area=’北京’
當(dāng)我們有如上查詢時(shí),?先根據(jù)時(shí)間段定位到segment,然后根據(jù)appkey in (‘a(chǎn)ppkey1’,’appkey2’) and area=’北京’ 查到各?的bitmap:(appkey1(1000) or appkey2(0110)) and 北京(1100) = (1100) 也就是說(shuō),符合條件的列是第?行和第?行,這兩?的metric的和為125.
Druid在架構(gòu)上主要參考了Google的Dremel,PowerDrill。
Druid官方架構(gòu)圖
Druid核?架構(gòu)中包括如下節(jié)點(diǎn)(Druid 的所有功能都在同?個(gè)包,通過(guò)不同的命令啟動(dòng)):
簡(jiǎn)單來(lái)說(shuō):
總結(jié)下大致查詢鏈路,查詢打到Router, Router選擇對(duì)應(yīng)的broker,broker會(huì)根據(jù)查詢時(shí)間,查詢屬性等因素來(lái)進(jìn)行segment篩選。broker會(huì)查找到對(duì)應(yīng)的Historical跟MiddleManager節(jié)點(diǎn),這倆節(jié)點(diǎn)會(huì)重寫為子查詢,然后最終把結(jié)果匯總到broker,需要注意middleManager可以查詢沒(méi)有發(fā)布到歷史節(jié)點(diǎn)的數(shù)據(jù),這樣Druid可以進(jìn)行近實(shí)時(shí)查詢。
Druid通過(guò)下面三種優(yōu)化方法提高查詢性能:
目前Druid數(shù)據(jù)攝取主要有批量跟流式兩大類。
數(shù)據(jù)攝取
Druid的indexing-service即?持批量也支持流式,上表中的Native batch/本地批量索引和kafkaindexing-service(Pull)均使?用了了indexing-service,只不過(guò)通過(guò)攝取任務(wù)類型來(lái)區(qū)分。
Index Service是運(yùn)行索引相關(guān)任務(wù)的?可?性分布式服務(wù),它的架構(gòu)中包括了了Overlord、MiddleManager、Peon。簡(jiǎn)單理解:
index Service工作流程
在上圖中,通過(guò)index-service的方式批量攝取數(shù)據(jù),我們需要向Overlord提交?個(gè)索引任務(wù),Overlord接受任務(wù),通過(guò)Zookeeper將任務(wù)信息分配給MiddleManger,Middlemanager領(lǐng)取任務(wù)后創(chuàng)建Peon進(jìn)程,Peon通過(guò)Zookeeper向Overlord定期匯報(bào)任務(wù)狀態(tài)。
Druid?持批量數(shù)據(jù)攝?和實(shí)時(shí)流數(shù)據(jù)攝入兩種數(shù)據(jù)攝?方式,?論是哪種?式都得指定?個(gè)攝取規(guī)則?文件(Ingestion Spec)定義攝取的詳細(xì)規(guī)則(類似于Flume采集數(shù)據(jù)都得指定?個(gè)配置文件?樣)。
數(shù)據(jù)攝取時(shí)type可指定為index、index_hadoop、kafka這三種,然后可以嘗試通過(guò)本地、HDFS、Kafka準(zhǔn)備數(shù)據(jù)源,準(zhǔn)備好數(shù)據(jù)攝取規(guī)則文件。
Druid?直提供REST API進(jìn)行數(shù)據(jù)查詢,在0.10之前第三方提供SQL?持,但不是很成熟,從0.10開(kāi)始原生提供實(shí)驗(yàn)性SQL查詢功能,截?Druid0.12.3還是處于實(shí)驗(yàn)性階段。
查詢方式
用戶可通過(guò)REST API的方式將請(qǐng)求包裝為JSON格式進(jìn)行查詢,返回的結(jié)果也是JSON格式,接下來(lái)主要說(shuō)明下請(qǐng)求JSON的格式。
Filter就是過(guò)濾器,?用對(duì)維度進(jìn)行行篩選和過(guò)濾,滿?Filter的行將會(huì)被返回,類似sql中的where?句。
granularity 配置項(xiàng)指定查詢時(shí)的時(shí)間聚合粒度,查詢時(shí)的時(shí)間聚合粒度要 >= 創(chuàng)建索引時(shí)設(shè)置的索引粒度,druid提供了了三種類型的聚合粒度分別是:Simple、Duration、Period。
Simple :druid提供的固定時(shí)間粒度,?字符串串表示,默認(rèn)就是Simple,定義查詢規(guī)則的時(shí)候不需要顯示設(shè)置type配置項(xiàng),druid提供的常?用Simple粒度:
all:會(huì)將起始和結(jié)束時(shí)間內(nèi)所有數(shù)據(jù)聚合到?一起返回?一個(gè)結(jié)果集,
none:按照創(chuàng)建索引時(shí)的最?粒度做聚合計(jì)算,最?粒度是毫秒為單位,不推薦使?,性能較差
minute:以分鐘作為聚合的最?小粒度
fifteen_minute:15分鐘聚合
thirty_minute:30分鐘聚合
hour:?小時(shí)聚合
day:天聚合
month:按年年聚合
quarter:按季度聚合
Duration : 對(duì)Simple的補(bǔ)充,duration聚合粒度提供了了更更加靈活的粒度,不不只局限于Simple聚合粒度提供的固定聚合粒度,?是以毫秒為單位?定義聚合粒度。
?如兩小時(shí)做?次聚合可以設(shè)置duration配置項(xiàng)為7200000毫秒,
所以Simple聚合粒度不能夠滿?足的聚合粒度可以選擇使?用Duration聚合粒度。
注意:使?用Duration聚合粒度需要設(shè)置配置項(xiàng)type值為duration。
Period : 聚合粒度采?了?期格式,常?的?種時(shí)間跨度表示?法。
一小時(shí):PT1H
一周:P1W
?天:P1D
?月:P1M
注意: 使?Period聚合粒度需要設(shè)置配置項(xiàng)type值為period
聚合器在數(shù)據(jù)攝?和查詢是均可以使用,在數(shù)據(jù)攝?]入階段使?]用聚合器能夠在數(shù)據(jù)被查詢之前按照維度進(jìn)行聚合計(jì)算,提?查詢階段聚合計(jì)算性能,在查詢過(guò)程中,使?聚合器能夠?qū)崿F(xiàn)各種不同指標(biāo)的組合計(jì)算。
公共屬性:
計(jì)數(shù)聚合器,等同于sql語(yǔ)法中的count函數(shù),?于計(jì)算druid roll-up合并之后的數(shù)據(jù)條數(shù),并不是原始數(shù)據(jù)條數(shù)。
在定義數(shù)據(jù)模式指標(biāo)規(guī)則中必須添加?個(gè)count類型的計(jì)數(shù)指標(biāo)count;
{"type":"count","name":out_name}
如果想要查詢?cè)紨?shù)據(jù)攝?入多少條,在查詢時(shí)使?用longSum,JSON示例例如下:
{"type":"longSum","name":out_name,"fieldName":"count"}
求和聚合器,等同于sql語(yǔ)法中的sum函數(shù),druid提供兩種類型的聚合器,分別是long類型和double類型的聚合器。
longSum
doubleSum
floatSum
類似SQL語(yǔ)法中的Min/Max
longMin
longMax
doubleMin
doubleMax
floatMin
floatMax
原生 Druid 去重功能支持情況
僅支持單維度,構(gòu)建時(shí)需要基于該維度做 hash partition。
不能跨 interval 進(jìn)行計(jì)算。
cardinality agg,非精確,基于 hll 。查詢時(shí) hash 函數(shù)較耗費(fèi) CPU。
嵌套 group by,精確,耗費(fèi)資源。
社區(qū) DistinctCount 插件,精確,但是局限很大。
HyperUniques/Sketch,非精確,基于 hll,攝入時(shí)做計(jì)算,相比 cardinality agg 性能更高。
結(jié)論:Druid 缺乏一種支持預(yù)聚合、資源占用低、通用性強(qiáng)的精確去重支持。用戶可自己基于bitmap、unique做二次開(kāi)發(fā)精確去重。
Post-Aggregator可以對(duì)結(jié)果進(jìn)?行?次加工并輸出,最終的輸出既包含Aggregation的結(jié)果,也包含Post-Aggregator的結(jié)果,Post-Aggregator包含的類型:
druid的查詢分為三大類,分別是聚合查詢,元數(shù)據(jù)查詢以及普通查詢。
普通的查詢:
Select
Scan
Search
聚合查詢:
Timeseries
TopN
GroupBy
元數(shù)據(jù)查詢:
Time Bounding
Segment Metadata
DataSource Metadata
普通的查詢沒(méi)什么好講的,只有一個(gè)需要注意的點(diǎn),那就是select在查詢大量的數(shù)據(jù)的時(shí)候,很消耗內(nèi)存,如果沒(méi)有分頁(yè)的需求,可以用scan替代。
元數(shù)據(jù)的查詢,主要不是基于業(yè)務(wù)的查詢,而是對(duì)當(dāng)前表的屬性,或者是定義列的類型這一類屬性的查詢,比如xxx表中"country"是什么類型的數(shù)據(jù),xxx表收集數(shù)據(jù)起止時(shí)間,或者當(dāng)前分段的版本是什么之類的信息。
主要需要理解的是三種內(nèi)置的聚合查詢,本質(zhì)上做的操作是這樣的。
一般在查詢時(shí)需要指定若干參數(shù)的。
參考
Druid官網(wǎng):https://druid.apache.org
快手Druid實(shí)戰(zhàn):https://toutiao.io/posts/9pgmav/preview

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流