ClickHouse Better Practices

前言

經(jīng)過一個(gè)月的調(diào)研和快速試錯(cuò),我們的ClickHouse集群已經(jīng)正式投入生產(chǎn)環(huán)境喇聊,在此過程中總結(jié)出了部分有用的經(jīng)驗(yàn),現(xiàn)記錄如下蹦狂∈睦椋看官可去粗取精,按照自己項(xiàng)目中的實(shí)際情況采納之凯楔。(版本為19.16.14.65)

因?yàn)槲覀円隒lickHouse的時(shí)間并不算長(zhǎng)窜骄,還有很多要探索的,因此不敢妄稱“最佳實(shí)踐”摆屯,還是叫做“更佳實(shí)踐”比較好吧邻遏。

表相關(guān)事項(xiàng)

數(shù)據(jù)類型
  • 建表時(shí)能用數(shù)值型或日期時(shí)間型表示的字段,就不要用字符串——全String類型在以Hive為中心的數(shù)倉(cāng)建設(shè)中常見虐骑,但CK環(huán)境不應(yīng)受此影響准验。
  • 直接用DateTime表示時(shí)間列,而不是用整形的時(shí)間戳廷没。因?yàn)镃K中DateTime的底層就是時(shí)間戳沟娱,效率高,可讀性好腕柜,且轉(zhuǎn)換函數(shù)豐富济似。
  • 官方已經(jīng)指出Nullable類型幾乎總是會(huì)拖累性能,因?yàn)榇鎯?chǔ)Nullable列時(shí)需要?jiǎng)?chuàng)建一個(gè)額外的文件來存儲(chǔ)NULL的標(biāo)記盏缤,并且Nullable列無法被索引砰蠢。因此除非極特殊情況,應(yīng)直接使用字段默認(rèn)值表示空唉铜,或者自行指定一個(gè)在業(yè)務(wù)中無意義的值(例如用-1表示沒有商品ID)台舱。
分區(qū)和索引
  • 事實(shí)表必須分區(qū),分區(qū)粒度根據(jù)業(yè)務(wù)特點(diǎn)決定,不宜過粗或過細(xì)竞惋。我們當(dāng)前都是按天分區(qū)柜去,按小時(shí)、周拆宛、月分區(qū)也比較常見(系統(tǒng)表中的query_log嗓奢、trace_log表默認(rèn)就是按月分區(qū)的)。
  • 必須指定索引列浑厚,在絕大多數(shù)查詢的WHERE語(yǔ)句中都會(huì)用到的列適合作為索引股耽。CK的索引非MySQL的B樹索引,而是類似Kafka log風(fēng)格的稀疏索引钳幅,故不用考慮最左原則物蝙,但是建議日期列和區(qū)分度較低的列在前,區(qū)分度較高的列在后敢艰。

訂正:根據(jù)稀疏索引的規(guī)律诬乞,建議查詢中更經(jīng)常用做查詢條件(WHERE謂詞)的列在前,較不經(jīng)常用做查詢條件的列在后钠导。如果有兩列在WHERE謂詞中出現(xiàn)的頻率大致相同丽惭,則基數(shù)較大的列(即區(qū)分度較高的列)在前,基數(shù)較小的列(區(qū)分度較低的列)在后辈双。另外责掏,基數(shù)特別大的列(如訂單ID等)不建議直接用作索引。

  • 表的索引粒度index_granularity不建議調(diào)整湃望,保持默認(rèn)值8192即可换衬。
表參數(shù)
  • 生產(chǎn)環(huán)境中提供線上服務(wù)的表均采用復(fù)制表與分布式表相結(jié)合,即Replicated*MergeTree+Distributed引擎证芭。分布式表的表名為本地表名加上_all后綴瞳浦。
  • 如果表中不是必須保留全量歷史數(shù)據(jù),建議指定TTL废士,可以免去手動(dòng)過期歷史數(shù)據(jù)的麻煩叫潦。TTL也可以通過ALTER TABLE語(yǔ)句隨時(shí)修改。
  • 建議指定use_minimalistic_part_header_in_zookeeper = 1設(shè)置項(xiàng)官硝,能夠顯著壓縮表元數(shù)據(jù)在ZooKeeper中的存儲(chǔ)矗蕊。該項(xiàng)也可以寫入config.xml中的<merge_tree>一節(jié)。

查詢相關(guān)事項(xiàng)

單表查詢
  • 所有應(yīng)用層查詢禁止SELECT *氢架。
  • 查詢分區(qū)表必須指定分區(qū)(所謂partition pruning)傻咖,不能全表查詢。
  • 大規(guī)模數(shù)據(jù)集上的ORDER BY要加LIMIT限制岖研。
  • 結(jié)果集上的簡(jiǎn)單運(yùn)算(例如SELECT pv, uv, pv / uv as ratio...中的ratio)可以在前端展示時(shí)再進(jìn)行卿操,減少SQL中不必要的虛擬列。
  • 業(yè)務(wù)場(chǎng)景非強(qiáng)制要求100%準(zhǔn)確的基數(shù)計(jì)量,應(yīng)該用uniq()函數(shù)而不是uniqExact()函數(shù)或DISTINCT關(guān)鍵字害淤。uniq()底層采用HyperLogLog實(shí)現(xiàn)扇雕,能夠以低于1%的精度損失換來極大的性能提升。
  • 能夠重用的模式化查詢(如固定刷新的BI報(bào)表窥摄、熱力圖等)一定要做成物化視圖镶奉,并在物化視圖上查詢出結(jié)果,可以避免大量的重復(fù)計(jì)算溪王。關(guān)于其用法腮鞍,可參見之前寫過的《物化視圖簡(jiǎn)介與ClickHouse中的應(yīng)用示例》值骇。
多表查詢
  • 當(dāng)兩表關(guān)聯(lián)查詢只需要從左表出結(jié)果時(shí)莹菱,建議用IN而不是JOIN,即寫成SELECT ... FROM left_table WHERE join_key IN (SELECT ... FROM right_table)的風(fēng)格吱瘩。
  • 不管是LEFT道伟、RIGHT還是INNER JOIN操作,小表都必須放在右側(cè)使碾。因?yàn)镃K默認(rèn)在大多數(shù)情況下都用hash join算法蜜徽,左表固定為probe table,右表固定為build table且被廣播票摇。
  • CK的查詢優(yōu)化器比較弱拘鞋,JOIN操作的謂詞不會(huì)下推,因此一定要先做完過濾矢门、聚合等操作盆色,再在結(jié)果集上做JOIN。這點(diǎn)與我們寫其他平臺(tái)SQL語(yǔ)句的習(xí)慣很不同祟剔,初期尤其需要注意隔躲。
  • 兩張分布式表上的IN和JOIN之前必須加上GLOBAL關(guān)鍵字际长。如果不加GLOBAL關(guān)鍵字的話详瑞,每個(gè)節(jié)點(diǎn)都會(huì)單獨(dú)發(fā)起一次對(duì)右表的查詢均驶,而右表又是分布式表多柑,就導(dǎo)致右表一共會(huì)被查詢N2次(N是該分布式表的shard數(shù)量)搪泳,這就是所謂的查詢放大夷磕,會(huì)帶來不小的overhead帮匾。加上GLOBAL關(guān)鍵字之后查描,右表只會(huì)在接收查詢請(qǐng)求的那個(gè)節(jié)點(diǎn)查詢一次耗溜,并將其分發(fā)到其他節(jié)點(diǎn)上买置。
負(fù)載均衡

對(duì)于循環(huán)復(fù)制拓?fù)涞募海樵兎植际奖淼呢?fù)載均衡策略(即load_balancing)設(shè)為first_or_random是最優(yōu)的强霎,能夠充分利用機(jī)器page cache的同時(shí)忿项,在有replica失敗時(shí)也能盡量保證負(fù)載平均分配。詳情可見這個(gè)issue

寫入相關(guān)事項(xiàng)

  • 寫入分布式表的底表轩触,而不直接寫分布式表寞酿。在之前的《ClickHouse復(fù)制表、分布式表機(jī)制與使用方法》一文中已有說明脱柱。
  • 不要做小批量零碎的寫入伐弹,每批次至少千條級(jí)別,避免給merge造成太大壓力榨为。
  • 不要同時(shí)寫入太多個(gè)分區(qū)惨好,或者寫入過快(官方給出的閾值為1秒1次),容易因?yàn)閙erge的速度跟不上parts生成的速度而報(bào)出"too many parts"的錯(cuò)誤随闺。如果正常情況下還會(huì)出現(xiàn)此錯(cuò)誤日川,建議在CPU資源允許的情況下適當(dāng)調(diào)大后臺(tái)任務(wù)線程數(shù)background_pool_size,默認(rèn)值為16矩乐。

運(yùn)維相關(guān)事項(xiàng)

CPU

CK的“快”與其對(duì)CPU的積極利用密不可分龄句,所以CPU的單核性能和多核性能都要盡量好一點(diǎn),16核32線程左右且?guī)л^高的睿頻比較合適散罕。CK設(shè)置中的max_threads參數(shù)控制單個(gè)查詢所能利用的CPU線程數(shù)分歇,默認(rèn)與本機(jī)CPU的物理核心數(shù)相同,如果服務(wù)器是CK獨(dú)占的欧漱,那么就不用改职抡,否則就改小些。

在監(jiān)控集群時(shí)误甚,CPU指標(biāo)也是最重要的缚甩。實(shí)測(cè)當(dāng)單個(gè)CK Server節(jié)點(diǎn)的CPU使用率超過70%時(shí),服務(wù)就不太穩(wěn)定了靶草。

內(nèi)存

官方文檔建議單機(jī)物理內(nèi)存128G左右蹄胰。實(shí)測(cè)CK在我們的應(yīng)用場(chǎng)景下內(nèi)存占用并不激進(jìn),每線程對(duì)應(yīng)1G內(nèi)存非常綽綽有余奕翔,即max_threads設(shè)為20的話裕寨,max_memory_usage參數(shù)設(shè)為20G(懶得打辣么多0了)。為了不干擾系統(tǒng)的正常運(yùn)行派继,也應(yīng)配置所有查詢能利用的最大內(nèi)存參數(shù)max_memory_usage_for_all_queries宾袜,取物理內(nèi)存的80%左右即可。

另外驾窟,CK在執(zhí)行GROUP BY聚合邏輯的過程中很有可能超出內(nèi)存限制庆猫,因此也建議設(shè)置max_bytes_before_external_group_by參數(shù)。在內(nèi)存占用超出此閾值之后绅络,就會(huì)spill到磁盤繼續(xù)操作月培,且性能沒有降低特別多嘁字。官方建議將它設(shè)置為max_memory_usage的一半。

存儲(chǔ)

CK不太挑存儲(chǔ)介質(zhì)杉畜,普通7200rpm SATA HDD都可以用纪蜒,也可以配置磁盤陣列,建議RAID10或者RAID6此叠。但是如果為了快速響應(yīng)纯续,或者多數(shù)查詢的數(shù)據(jù)量都很大,還是建議上SSD(我們就是如此)灭袁。另外猬错,CK還支持基于配置文件的多盤存儲(chǔ)、冷熱數(shù)據(jù)分離和存儲(chǔ)策略(storage policy)設(shè)置茸歧,在特定場(chǎng)景下可能會(huì)很有用倦炒。我們未實(shí)操過,不多講了举娩。

ZooKeeper

千萬(wàn)要調(diào)教好ZooKeeper集群析校,一旦ZK不可用构罗,復(fù)制表和分布式表就不可用了铜涉。ZK的數(shù)據(jù)量基本上與CK的數(shù)據(jù)量成正相關(guān),所以一定要配置自動(dòng)清理:

autopurge.purgeInterval = 1
autopurge.snapRetainCount = 5

另外遂唧,ZK的log文件和snapshot文件建議分不同的盤存儲(chǔ)芙代,盡量減少follower從leader同步的磁盤壓力,且余量必須要留足盖彭,畢竟硬盤的成本不算高纹烹。

The End

上文中還涉及到一些比較重要的知識(shí)點(diǎn),如MergeTree索引的結(jié)構(gòu)召边,JOIN語(yǔ)句的執(zhí)行過程铺呵,CK與ZK的交互等等,今后有時(shí)間會(huì)分別寫文章詳細(xì)講解隧熙。

618之前事情一直都會(huì)比較多片挂,希望一切順利。今天先這樣吧贞盯。

民那晚安晚安音念。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市躏敢,隨后出現(xiàn)的幾起案子闷愤,更是在濱河造成了極大的恐慌,老刑警劉巖件余,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讥脐,死亡現(xiàn)場(chǎng)離奇詭異遭居,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)旬渠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門魏滚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人坟漱,你說我怎么就攤上這事鼠次。” “怎么了芋齿?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵腥寇,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我觅捆,道長(zhǎng)赦役,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任栅炒,我火速辦了婚禮掂摔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赢赊。我一直安慰自己乙漓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布释移。 她就那樣靜靜地躺著叭披,像睡著了一般。 火紅的嫁衣襯著肌膚如雪玩讳。 梳的紋絲不亂的頭發(fā)上涩蜘,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音熏纯,去河邊找鬼同诫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛樟澜,可吹牛的內(nèi)容都是我干的误窖。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼往扔,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼贩猎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起萍膛,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤吭服,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蝗罗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艇棕,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝌戒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沼琉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片北苟。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖打瘪,靈堂內(nèi)的尸體忽然破棺而出友鼻,到底是詐尸還是另有隱情,我是刑警寧澤闺骚,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布彩扔,位于F島的核電站,受9級(jí)特大地震影響僻爽,放射性物質(zhì)發(fā)生泄漏虫碉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一胸梆、第九天 我趴在偏房一處隱蔽的房頂上張望敦捧。 院中可真熱鬧,春花似錦碰镜、人聲如沸兢卵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)济蝉。三九已至杰刽,卻和暖如春菠发,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贺嫂。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工滓鸠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人第喳。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓糜俗,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親曲饱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子悠抹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容