0 - 前言
ClickHouse是近期備受關(guān)注的開源列式存儲數(shù)據(jù)庫,主要用于數(shù)據(jù)分析(OLAP)領(lǐng)域咽筋。目前國內(nèi)社區(qū)火熱,各大廠紛紛跟進(jìn)大規(guī)模使用:
- 今日頭條內(nèi)部用來做用戶行為分析徊件,內(nèi)部一共幾千個ClickHouse節(jié)點奸攻,單機(jī)群最大1200節(jié)點,總數(shù)據(jù)量幾十PB虱痕,日增原始數(shù)據(jù)300TB左右睹耐。
- 騰訊內(nèi)部用ClickHouse做游戲數(shù)據(jù)分析,并且為之建立了一整套監(jiān)控運維體系部翘。
- 攜程內(nèi)部從18年7月份開始接入試用硝训,目前80%的業(yè)務(wù)都跑在ClickHouse上。每天數(shù)據(jù)增量十多億新思,近百萬次查詢請求窖梁。
- 快手內(nèi)部也在使用ClickHouse,存儲總量大約10PB夹囚, 每天新增200TB窄绒, 90%查詢小于3S。
在國外崔兴,Yandex內(nèi)部有數(shù)百節(jié)點用于做用戶點擊行為分析彰导,CloudFlare蛔翅、Spotify等頭部公司也在使用。
在社區(qū)方面位谋,github star數(shù)目增速驚人山析。
在DB-engines排名上,如下圖中紅色曲線所示掏父。ClickHouse開源時間雖短笋轨,但是增勢迅猛。
1 - OLAP場景的特點
讀多于寫
不同于事務(wù)處理(OLTP)的場景赊淑,比如電商場景中加購物車爵政、下單、支付等需要在原地進(jìn)行大量insert陶缺、update钾挟、delete操作,數(shù)據(jù)分析(OLAP)場景通常是將數(shù)據(jù)批量導(dǎo)入后饱岸,進(jìn)行任意維度的靈活探索掺出、BI工具洞察、報表制作等苫费。數(shù)據(jù)一次性寫入后汤锨,分析師需要嘗試從各個角度對數(shù)據(jù)做挖掘、分析百框,直到發(fā)現(xiàn)其中的商業(yè)價值闲礼、業(yè)務(wù)變化趨勢等信息。這是一個需要反復(fù)試錯铐维、不斷調(diào)整位仁、持續(xù)優(yōu)化的過程,其中數(shù)據(jù)的讀取次數(shù)遠(yuǎn)多于寫入次數(shù)方椎。這就要求底層數(shù)據(jù)庫為這個特點做專門設(shè)計聂抢,而不是盲目采用傳統(tǒng)數(shù)據(jù)庫的技術(shù)架構(gòu)。
大寬表棠众,讀大量行但是少量列琳疏,結(jié)果集較小
在OLAP場景中,通常存在一張或是幾張多列的大寬表闸拿,列數(shù)高達(dá)數(shù)百甚至數(shù)千列空盼。對數(shù)據(jù)分析處理時,選擇其中的少數(shù)幾列作為維度列新荤、其他少數(shù)幾列作為指標(biāo)列揽趾,然后對全表或某一個較大范圍內(nèi)的數(shù)據(jù)做聚合計算。這個過程會掃描大量的行數(shù)據(jù)苛骨,但是只用到了其中的少數(shù)列篱瞎。而聚合計算的結(jié)果集相比于動輒數(shù)十億的原始數(shù)據(jù)苟呐,也明顯小得多。
數(shù)據(jù)批量寫入俐筋,且數(shù)據(jù)不更新或少更新
OLTP類業(yè)務(wù)對于延時(Latency)要求更高牵素,要避免讓客戶等待造成業(yè)務(wù)損失;而OLAP類業(yè)務(wù)澄者,由于數(shù)據(jù)量非常大笆呆,通常更加關(guān)注寫入吞吐(Throughput),要求海量數(shù)據(jù)能夠盡快導(dǎo)入完成粱挡。一旦導(dǎo)入完成赠幕,歷史數(shù)據(jù)往往作為存檔,不會再做更新询筏、刪除操作榕堰。
無需事務(wù),數(shù)據(jù)一致性要求低
OLAP類業(yè)務(wù)對于事務(wù)需求較少屈留,通常是導(dǎo)入歷史日志數(shù)據(jù),或搭配一款事務(wù)型數(shù)據(jù)庫并實時從事務(wù)型數(shù)據(jù)庫中進(jìn)行數(shù)據(jù)同步测蘑。多數(shù)OLAP系統(tǒng)都支持最終一致性灌危。
靈活多變,不適合預(yù)先建模
分析場景下碳胳,隨著業(yè)務(wù)變化要及時調(diào)整分析維度勇蝙、挖掘方法,以盡快發(fā)現(xiàn)數(shù)據(jù)價值挨约、更新業(yè)務(wù)指標(biāo)味混。而數(shù)據(jù)倉庫中通常存儲著海量的歷史數(shù)據(jù),調(diào)整代價十分高昂诫惭。預(yù)先建模技術(shù)雖然可以在特定場景中加速計算翁锡,但是無法滿足業(yè)務(wù)靈活多變的發(fā)展需求,維護(hù)成本過高夕土。
2 - ClickHouse存儲層
ClickHouse從OLAP場景需求出發(fā)馆衔,定制開發(fā)了一套全新的高效列式存儲引擎,并且實現(xiàn)了數(shù)據(jù)有序存儲怨绣、主鍵索引角溃、稀疏索引、數(shù)據(jù)Sharding篮撑、數(shù)據(jù)Partitioning减细、TTL、主備復(fù)制等豐富功能赢笨。以上功能共同為ClickHouse極速的分析性能奠定了基礎(chǔ)未蝌。
列式存儲
與行存將每一行的數(shù)據(jù)連續(xù)存儲不同驮吱,列存將每一列的數(shù)據(jù)連續(xù)存儲。示例圖如下:
相比于行式存儲树埠,列式存儲在分析場景下有著許多優(yōu)良的特性:
- 如前所述糠馆,分析場景中往往需要讀大量行但是少數(shù)幾個列。在行存模式下怎憋,數(shù)據(jù)按行連續(xù)存儲又碌,所有列的數(shù)據(jù)都存儲在一個block中,不參與計算的列在IO時也要全部讀出绊袋,讀取操作被嚴(yán)重放大毕匀。而列存模式下,只需要讀取參與計算的列即可癌别,極大的減低了IO cost皂岔,加速了查詢。
- 同一列中的數(shù)據(jù)屬于同一類型展姐,壓縮效果顯著躁垛。列存往往有著高達(dá)十倍甚至更高的壓縮比,節(jié)省了大量的存儲空間圾笨,降低了存儲成本教馆。
- 更高的壓縮比意味著更小的data size,從磁盤中讀取相應(yīng)數(shù)據(jù)耗時更短擂达。
- 自由的壓縮算法選擇土铺。不同列的數(shù)據(jù)具有不同的數(shù)據(jù)類型,適用的壓縮算法也就不盡相同板鬓”螅可以針對不同列類型,選擇最合適的壓縮算法俭令。
- 高壓縮比后德,意味著同等大小的內(nèi)存能夠存放更多數(shù)據(jù),系統(tǒng)cache效果更好抄腔。
官方數(shù)據(jù)顯示探遵,通過使用列存,在某些分析場景下妓柜,能夠獲得100倍甚至更高的加速效應(yīng)箱季。
數(shù)據(jù)有序存儲
ClickHouse支持在建表時,指定將數(shù)據(jù)按照某些列進(jìn)行sort by棍掐。
排序后藏雏,保證了相同sort key的數(shù)據(jù)在磁盤上連續(xù)存儲,且有序擺放。在進(jìn)行等值掘殴、范圍查詢時赚瘦,where條件命中的數(shù)據(jù)都緊密存儲在一個或若干個連續(xù)的Block中,而不是分散的存儲在任意多個Block奏寨, 大幅減少需要IO的block數(shù)量起意。另外,連續(xù)IO也能夠充分利用操作系統(tǒng)page cache的預(yù)取能力病瞳,減少page fault揽咕。
主鍵索引
ClickHouse支持主鍵索引,它將每列數(shù)據(jù)按照index granularity(默認(rèn)8192行)進(jìn)行劃分套菜,每個index granularity的開頭第一行被稱為一個mark行亲善。主鍵索引存儲該mark行對應(yīng)的primary key的值。
對于where條件中含有primary key的查詢逗柴,通過對主鍵索引進(jìn)行二分查找蛹头,能夠直接定位到對應(yīng)的index granularity,避免了全表掃描從而加速查詢戏溺。
但是值得注意的是:ClickHouse的主鍵索引與MySQL等數(shù)據(jù)庫不同渣蜗,它并不用于去重,即便primary key相同的行旷祸,也可以同時存在于數(shù)據(jù)庫中耕拷。
稀疏索引
ClickHouse支持對任意列創(chuàng)建任意數(shù)量的稀疏索引。其中被索引的value可以是任意的合法SQL Expression肋僧,并不僅僅局限于對column value本身進(jìn)行索引斑胜。之所以叫稀疏索引控淡,是因為它本質(zhì)上是對一個完整index granularity(默認(rèn)8192行)的統(tǒng)計信息嫌吠,并不會具體記錄每一行在文件中的位置。目前支持的稀疏索引類型包括:
- minmax: 以index granularity為單位掺炭,存儲指定表達(dá)式計算后的min辫诅、max值;在等值和范圍查詢中能夠幫助快速跳過不滿足要求的塊涧狮,減少IO炕矮。
- set(max_rows):以index granularity為單位厕隧,存儲指定表達(dá)式的distinct value集合尽棕,用于快速判斷等值查詢是否命中該塊地啰,減少IO在扰。
- ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed):將string進(jìn)行ngram分詞后橄维,構(gòu)建bloom filter梧田,能夠優(yōu)化等值蹂午、like窑业、in等查詢條件愿汰。
- tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed): 與ngrambf_v1類似困后,區(qū)別是不使用ngram進(jìn)行分詞乐纸,而是通過標(biāo)點符號進(jìn)行詞語分割。
- bloom_filter([false_positive]):對指定列構(gòu)建bloom filter摇予,用于加速等值汽绢、like、in等查詢條件的執(zhí)行侧戴。
數(shù)據(jù)Sharding
ClickHouse支持單機(jī)模式宁昭,也支持分布式集群模式。在分布式模式下救鲤,ClickHouse會將數(shù)據(jù)分為多個分片久窟,并且分布到不同節(jié)點上。不同的分片策略在應(yīng)對不同的SQL Pattern時本缠,各有優(yōu)勢斥扛。ClickHouse提供了豐富的sharding策略,讓業(yè)務(wù)可以根據(jù)實際需求選用丹锹。
- random隨機(jī)分片:寫入數(shù)據(jù)會被隨機(jī)分發(fā)到分布式集群中的某個節(jié)點上稀颁。
- constant固定分片:寫入數(shù)據(jù)會被分發(fā)到固定一個節(jié)點上。
- column value分片:按照某一列的值進(jìn)行hash分片楣黍。
- 自定義表達(dá)式分片:指定任意合法表達(dá)式匾灶,根據(jù)表達(dá)式被計算后的值進(jìn)行hash分片。
數(shù)據(jù)分片租漂,讓ClickHouse可以充分利用整個集群的大規(guī)模并行計算能力阶女,快速返回查詢結(jié)果。
更重要的是哩治,多樣化的分片功能秃踩,為業(yè)務(wù)優(yōu)化打開了想象空間。比如在hash sharding的情況下业筏,JOIN計算能夠避免數(shù)據(jù)shuffle憔杨,直接在本地進(jìn)行l(wèi)ocal join; 支持自定義sharding蒜胖,可以為不同業(yè)務(wù)和SQL Pattern定制最適合的分片策略消别;利用自定義sharding功能,通過設(shè)置合理的sharding expression可以解決分片間數(shù)據(jù)傾斜問題等台谢。
另外寻狂,sharding機(jī)制使得ClickHouse可以橫向線性拓展,構(gòu)建大規(guī)模分布式集群朋沮,從而具備處理海量數(shù)據(jù)的能力蛇券。
數(shù)據(jù)Partitioning
ClickHouse支持PARTITION BY子句,在建表時可以指定按照任意合法表達(dá)式進(jìn)行數(shù)據(jù)分區(qū)操作,比如通過toYYYYMM()將數(shù)據(jù)按月進(jìn)行分區(qū)怀读、toMonday()將數(shù)據(jù)按照周幾進(jìn)行分區(qū)诉位、對Enum類型的列直接每種取值作為一個分區(qū)等。
數(shù)據(jù)Partition在ClickHouse中主要有兩方面應(yīng)用:
- 在partition key上進(jìn)行分區(qū)裁剪菜枷,只查詢必要的數(shù)據(jù)苍糠。靈活的partition expression設(shè)置,使得可以根據(jù)SQL Pattern進(jìn)行分區(qū)設(shè)置啤誊,最大化的貼合業(yè)務(wù)特點岳瞭。
- 對partition進(jìn)行TTL管理,淘汰過期的分區(qū)數(shù)據(jù)蚊锹。
數(shù)據(jù)TTL
在分析場景中瞳筏,數(shù)據(jù)的價值隨著時間流逝而不斷降低,多數(shù)業(yè)務(wù)出于成本考慮只會保留最近幾個月的數(shù)據(jù)牡昆,ClickHouse通過TTL提供了數(shù)據(jù)生命周期管理的能力姚炕。
ClickHouse支持幾種不同粒度的TTL:
- 列級別TTL:當(dāng)一列中的部分?jǐn)?shù)據(jù)過期后,會被替換成默認(rèn)值丢烘;當(dāng)全列數(shù)據(jù)都過期后柱宦,會刪除該列。
- 行級別TTL:當(dāng)某一行過期后播瞳,會直接刪除該行掸刊。
- 分區(qū)級別TTL:當(dāng)分區(qū)過期后,會直接刪除該分區(qū)赢乓。
高吞吐寫入能力
ClickHouse采用類LSM Tree的結(jié)構(gòu)忧侧,數(shù)據(jù)寫入后定期在后臺Compaction。通過類LSM tree的結(jié)構(gòu)牌芋,ClickHouse在數(shù)據(jù)導(dǎo)入時全部是順序append寫蚓炬,寫入后數(shù)據(jù)段不可更改,在后臺compaction時也是多個段merge sort后順序?qū)懟卮疟P姜贡。順序?qū)懙奶匦允杂酰浞掷昧舜疟P的吞吐能力棺棵,即便在HDD上也有著優(yōu)異的寫入性能楼咳。
官方公開benchmark測試顯示能夠達(dá)到50MB-200MB/s的寫入吞吐能力,按照每行100Byte估算烛恤,大約相當(dāng)于50W-200W條/s的寫入速度母怜。
有限支持delete、update
在分析場景中缚柏,刪除苹熏、更新操作并不是核心需求。ClickHouse沒有直接支持delete、update操作轨域,而是變相支持了mutation操作袱耽,語法為alter table delete where filter_expr,alter table update col=val where filter_expr
。
目前主要限制為刪除干发、更新操作為異步操作朱巨,需要后臺compation之后才能生效。
主備同步
ClickHouse通過主備復(fù)制提供了高可用能力枉长,主備架構(gòu)下支持無縫升級等運維操作冀续。而且相比于其他系統(tǒng)它的實現(xiàn)有著自己的特色:
- 默認(rèn)配置下,任何副本都處于active模式必峰,可以對外提供查詢服務(wù)洪唐;
- 可以任意配置副本個數(shù),副本數(shù)量可以從0個到任意多個吼蚁;
- 不同shard可以配置不提供副本個數(shù)凭需,用于解決單個shard的查詢熱點問題;
3 - ClickHouse計算層
ClickHouse在計算層做了非常細(xì)致的工作肝匆,竭盡所能榨干硬件能力功炮,提升查詢速度。它實現(xiàn)了單機(jī)多核并行术唬、分布式計算薪伏、向量化執(zhí)行與SIMD指令、代碼生成等多種重要技術(shù)粗仓。
多核并行
ClickHouse將數(shù)據(jù)劃分為多個partition嫁怀,每個partition再進(jìn)一步劃分為多個index granularity,然后通過多個CPU核心分別處理其中的一部分來實現(xiàn)并行數(shù)據(jù)處理借浊。
在這種設(shè)計下塘淑,單條Query就能利用整機(jī)所有CPU。極致的并行處理能力蚂斤,極大的降低了查詢延時存捺。
分布式計算
除了優(yōu)秀的單機(jī)并行處理能力,ClickHouse還提供了可線性拓展的分布式計算能力曙蒸。ClickHouse會自動將查詢拆解為多個task下發(fā)到集群中捌治,然后進(jìn)行多機(jī)并行處理,最后把結(jié)果匯聚到一起纽窟。
在存在多副本的情況下肖油,ClickHouse提供了多種query下發(fā)策略:
- 隨機(jī)下發(fā):在多個replica中隨機(jī)選擇一個;
- 最近hostname原則:選擇與當(dāng)前下發(fā)機(jī)器最相近的hostname節(jié)點臂港,進(jìn)行query下發(fā)森枪。在特定的網(wǎng)絡(luò)拓?fù)湎率硬梢越档途W(wǎng)絡(luò)延時。而且能夠確保query下發(fā)到固定的replica機(jī)器县袱,充分利用系統(tǒng)cache浑娜。
- in order:按照特定順序逐個嘗試下發(fā),當(dāng)前一個replica不可用時式散,順延到下一個replica棚愤;
- first or random:在In Order模式下,當(dāng)?shù)谝粋€replica不可用時杂数,所有workload都會積壓到第二個Replica宛畦,導(dǎo)致負(fù)載不均衡。first or random解決了這個問題:當(dāng)?shù)谝粋€replica不可用時揍移,隨機(jī)選擇一個其他replica次和,從而保證其余replica間負(fù)載均衡。另外在跨region復(fù)制場景下那伐,通過設(shè)置第一個replica為本region內(nèi)的副本踏施,可以顯著降低網(wǎng)絡(luò)延時;
向量化執(zhí)行與SIMD
ClickHouse不僅將數(shù)據(jù)按列存儲罕邀,而且按列進(jìn)行計算畅形。傳統(tǒng)OLTP數(shù)據(jù)庫通常采用按行計算,原因是事務(wù)處理中以點查為主诉探,SQL計算量小日熬,實現(xiàn)這些技術(shù)的收益不夠明顯。但是在分析場景下肾胯,單個SQL所涉及計算量可能極大竖席,將每行作為一個基本單元進(jìn)行處理會帶來嚴(yán)重的性能損耗:
- 對每一行數(shù)據(jù)都要調(diào)用相應(yīng)的函數(shù),函數(shù)調(diào)用開銷占比高敬肚;
- 存儲層按列存儲數(shù)據(jù)毕荐,在內(nèi)存中也按列組織,但是計算層按行處理艳馒,無法充分利用CPU cache的預(yù)讀能力憎亚,造成CPU Cache miss嚴(yán)重;
- 按行處理弄慰,無法利用高效的SIMD指令第美;
ClickHouse實現(xiàn)了向量執(zhí)行引擎(Vectorized execution engine),對內(nèi)存中的列式數(shù)據(jù)曹动,一個batch調(diào)用一次SIMD指令(而非每一行調(diào)用一次)斋日,不僅減少了函數(shù)調(diào)用次數(shù)牲览、降低了cache miss墓陈,而且可以充分發(fā)揮SIMD指令的并行能力恶守,大幅縮短了計算耗時。向量執(zhí)行引擎贡必,通常能夠帶來數(shù)倍的性能提升兔港。
動態(tài)代碼生成Runtime Codegen
在經(jīng)典的數(shù)據(jù)庫實現(xiàn)中,通常對表達(dá)式計算采用火山模型仔拟,也即將查詢轉(zhuǎn)換成一個個operator衫樊,比如HashJoin、Scan利花、IndexScan科侈、Aggregation等。為了連接不同算子炒事,operator之間采用統(tǒng)一的接口臀栈,比如open/next/close。在每個算子內(nèi)部都實現(xiàn)了父類的這些虛函數(shù)挠乳,在分析場景中單條SQL要處理數(shù)據(jù)通常高達(dá)數(shù)億行权薯,虛函數(shù)的調(diào)用開銷不再可以忽略不計。另外睡扬,在每個算子內(nèi)部都要考慮多種變量盟蚣,比如列類型、列的size卖怜、列的個數(shù)等屎开,存在著大量的if-else分支判斷導(dǎo)致CPU分支預(yù)測失效。
ClickHouse實現(xiàn)了Expression級別的runtime codegen马靠,動態(tài)地根據(jù)當(dāng)前SQL直接生成代碼牍戚,然后編譯執(zhí)行。如下圖例子所示虑粥,對于Expression直接生成代碼如孝,不僅消除了大量的虛函數(shù)調(diào)用(即圖中多個function pointer的調(diào)用),而且由于在運行時表達(dá)式的參數(shù)類型娩贷、個數(shù)等都是已知的第晰,也消除了不必要的if-else分支判斷。
近似計算
近似計算以損失一定結(jié)果精度為代價彬祖,極大地提升查詢性能茁瘦。在海量數(shù)據(jù)處理中,近似計算價值更加明顯储笑。
ClickHouse實現(xiàn)了多種近似計算功能:
- 近似估算distinct values甜熔、中位數(shù),分位數(shù)等多種聚合函數(shù)突倍;
- 建表DDL支持SAMPLE BY子句腔稀,支持對于數(shù)據(jù)進(jìn)行抽樣處理盆昙;
復(fù)雜數(shù)據(jù)類型支持
ClickHouse還提供了array、json焊虏、tuple淡喜、set等復(fù)合數(shù)據(jù)類型,支持業(yè)務(wù)schema的靈活變更诵闭。
4 - 結(jié)語
近年來ClickHouse發(fā)展趨勢迅猛炼团,社區(qū)和大廠都紛紛跟進(jìn)使用。本文嘗試從OLAP場景的需求出發(fā)疏尿,介紹了ClickHouse存儲層瘟芝、計算層的主要設(shè)計。ClickHouse實現(xiàn)了大多數(shù)當(dāng)前主流的數(shù)據(jù)分析技術(shù)褥琐,具有明顯的技術(shù)優(yōu)勢:
- 提供了極致的查詢性能:開源公開benchmark顯示比傳統(tǒng)方法快1001000倍模狭,提供50MB200MB/s的高吞吐實時導(dǎo)入能力);
- 以極低的成本存儲海量數(shù)據(jù): 借助于精心設(shè)計的列存踩衩、高效的數(shù)據(jù)壓縮算法嚼鹉,提供高達(dá)10倍的壓縮比,大幅提升單機(jī)數(shù)據(jù)存儲和計算能力驱富,大幅降低使用成本锚赤,是構(gòu)建海量數(shù)據(jù)倉庫的絕佳方案。
- 簡單靈活又不失強(qiáng)大:提供完善SQL支持褐鸥,上手十分簡單线脚;提供json、map叫榕、array等靈活數(shù)據(jù)類型適配業(yè)務(wù)快速變化浑侥;同時支持近似計算、概率數(shù)據(jù)結(jié)構(gòu)等應(yīng)對海量數(shù)據(jù)處理晰绎。
相比于開源社區(qū)的其他幾項分析型技術(shù)寓落,如Druid、Presto荞下、Impala伶选、Kylin、ElasticSearch等尖昏,ClickHouse更是一整套完善的解決方案仰税,它自包含了存儲和計算能力(無需額外依賴其他存儲組件),完全自主實現(xiàn)了高可用抽诉,而且支持完整的SQL語法包括JOIN等陨簇,技術(shù)上有著明顯優(yōu)勢。相比于hadoop體系迹淌,以數(shù)據(jù)庫的方式來做大數(shù)據(jù)處理更加簡單易用河绽,學(xué)習(xí)成本低且靈活度高己单。當(dāng)前社區(qū)仍舊在迅猛發(fā)展中,相信后續(xù)會有越來越多好用的功能出現(xiàn)葵姥。