本文轉(zhuǎn)自 | 攜程技術(shù)中心 作者 | 蔡岳毅
作者簡介:
蔡岳毅,攜程酒店大數(shù)據(jù)高級研發(fā)經(jīng)理纤垂,負(fù)責(zé)酒店數(shù)據(jù)智能平臺研發(fā)矾策,大數(shù)據(jù)技術(shù)創(chuàng)新工作。喜歡探索研究大數(shù)據(jù)的開源技術(shù)框架峭沦。
1 - 背景
- 攜程酒店每天有上千表贾虽,累計(jì)十多億數(shù)據(jù)更新,如何保證數(shù)據(jù)更新過程中生產(chǎn)應(yīng)用高可用吼鱼;
- 每天有將近百萬次數(shù)據(jù)查詢請求蓬豁,用戶可以從粗粒度國家省份城市匯總不斷下鉆到酒店,房型粒度的數(shù)據(jù)菇肃,我們往往無法對海量的明細(xì)數(shù)據(jù)做進(jìn)一步層次的預(yù)聚合地粪,大量的關(guān)鍵業(yè)務(wù)數(shù)據(jù)都是好幾億數(shù)據(jù)關(guān)聯(lián)權(quán)限,關(guān)聯(lián)基礎(chǔ)信息琐谤,根據(jù)用戶場景獲取不同維度的匯總數(shù)據(jù)蟆技;
- 為了讓用戶無論在app端還是pc端查詢數(shù)據(jù)提供秒出的效果,我們需要不斷的探索,研究找到最合適的技術(shù)框架质礼;
對此旺聚,我們嘗試過關(guān)系型數(shù)據(jù)庫,但千萬級表關(guān)聯(lián)數(shù)據(jù)庫基本上不太可能做到秒出眶蕉,考慮過Sharding砰粹,但數(shù)據(jù)量大,各種成本都很高造挽。熱數(shù)據(jù)存儲到ElasticSearch碱璃,但無法跨索引關(guān)聯(lián),導(dǎo)致不得不做寬表饭入,因?yàn)闄?quán)限厘贼,酒店信息會變,所以每次要刷全量數(shù)據(jù)圣拄,不適用于大表更新,維護(hù)成本也很高毁欣。Redis鍵值對存儲無法做到實(shí)時(shí)匯總庇谆,也測試過Presto,GreenPlum凭疮,kylin饭耳,真正讓我們停下來深入研究,不斷的擴(kuò)展使用場景的是ClickHouse执解。
2 - ClickHouse介紹
ClickHouse是一款用于大數(shù)據(jù)實(shí)時(shí)分析的列式數(shù)據(jù)庫管理系統(tǒng)寞肖,而非數(shù)據(jù)庫。通過向量化執(zhí)行以及對cpu底層指令集(SIMD)的使用衰腌,它可以對海量數(shù)據(jù)進(jìn)行并行處理新蟆,從而加快數(shù)據(jù)的處理速度。
主要優(yōu)點(diǎn)有:
- 為了高效的使用CPU右蕊,數(shù)據(jù)不僅僅按列存儲琼稻,同時(shí)還按向量進(jìn)行處理;
- 數(shù)據(jù)壓縮空間大饶囚,減少io帕翻;處理單查詢高吞吐量每臺服務(wù)器每秒最多數(shù)十億行;
- 索引非B樹結(jié)構(gòu)萝风,不需要滿足最左原則嘀掸;只要過濾條件在索引列中包含即可;即使在使用的數(shù)據(jù)不在索引中规惰,由于各種并行處理機(jī)制ClickHouse全表掃描的速度也很快睬塌;
- 寫入速度非常快,50-200M/s衫仑,對于大量的數(shù)據(jù)更新非常適用梨与;
ClickHouse并非萬能的,正因?yàn)镃lickHouse處理速度快文狱,所以也是需要為“快”付出代價(jià)粥鞋。選擇ClickHouse需要有下面注意以下幾點(diǎn):
- 不支持事務(wù),不支持真正的刪除/更新瞄崇;
- 不支持高并發(fā)呻粹,官方建議qps為100,可以通過修改配置文件增加連接數(shù)苏研,但是在服務(wù)器足夠好的情況下等浊;
- sql滿足日常使用80%以上的語法,join寫法比較特殊摹蘑;最新版已支持類似sql的join筹燕,但性能不好;
- 盡量做1000條以上批量的寫入衅鹿,避免逐行insert或小批量的insert撒踪,update,delete操作大渤,因?yàn)镃lickHouse底層會不斷的做異步的數(shù)據(jù)合并制妄,會影響查詢性能,這個(gè)在做實(shí)時(shí)數(shù)據(jù)寫入的時(shí)候要盡量避開泵三;
- Clickhouse快是因?yàn)椴捎昧瞬⑿刑幚頇C(jī)制耕捞,即使一個(gè)查詢,也會用服務(wù)器一半的cpu去執(zhí)行烫幕,所以ClickHouse不能支持高并發(fā)的使用場景俺抽,默認(rèn)單查詢使用cpu核數(shù)為服務(wù)器核數(shù)的一半,安裝時(shí)會自動(dòng)識別服務(wù)器核數(shù)纬霞,可以通過配置文件修改該參數(shù)凌埂;
3 - ClickHouse在酒店數(shù)據(jù)智能平臺的實(shí)踐
3.1 - 數(shù)據(jù)更新
我們的主要數(shù)據(jù)源是Hive到ClickHouse,現(xiàn)在主要采用如下兩種方式:
Hive到MySql诗芜,再導(dǎo)入到ClickHouse
初期在DataX不支持hive到ClickHouse的數(shù)據(jù)導(dǎo)入瞳抓,我們是通過DataX將數(shù)據(jù)先導(dǎo)入mysql,再通過ClickHouse原生api將數(shù)據(jù)從mysql導(dǎo)入到ClickHouse伏恐。
為此我們設(shè)計(jì)了一套完整的數(shù)據(jù)導(dǎo)入流程孩哑,保證數(shù)據(jù)從hive到mysql再到ClickHouse能自動(dòng)化,穩(wěn)定的運(yùn)行翠桦,并保證數(shù)據(jù)在同步過程中線上應(yīng)用的高可用横蜒。
Hive到ClickHouse
DataX現(xiàn)在支持hive到ClickHouse胳蛮,我們部分?jǐn)?shù)據(jù)是通過DataX直接導(dǎo)入ClickHouse。但DataX暫時(shí)只支持導(dǎo)入丛晌,因?yàn)橐WC線上的高可用仅炊,所以僅僅導(dǎo)入是不夠的,還需要繼續(xù)依賴我們上面的一套流程來做ReName澎蛛,增量數(shù)據(jù)更新等操作抚垄。
針對數(shù)據(jù)高可用,我們對數(shù)據(jù)更新機(jī)制做了如下設(shè)計(jì):
全量數(shù)據(jù)導(dǎo)入流程
全量數(shù)據(jù)的導(dǎo)入過程比較簡單谋逻,僅需要將數(shù)據(jù)先導(dǎo)入到臨時(shí)表中呆馁,導(dǎo)入完成之后,再通過對正式表和臨時(shí)表進(jìn)行ReName操作毁兆,將對數(shù)據(jù)的讀取從老數(shù)據(jù)切換到新數(shù)據(jù)上來浙滤。
增量數(shù)據(jù)的導(dǎo)入過程
增量數(shù)據(jù)的導(dǎo)入過程,我們使用過兩個(gè)版本气堕。
由于ClickHouse的delete操作過于沉重纺腊,所以最早是通過刪除指定分區(qū)节猿,再把增量數(shù)據(jù)導(dǎo)入正式表的方式來實(shí)現(xiàn)的碌冶。
這種方式存在如下問題:一是在增量數(shù)據(jù)導(dǎo)入的過程中沸柔,數(shù)據(jù)的準(zhǔn)確性是不可保證的毫缆,如果增量數(shù)據(jù)越多,數(shù)據(jù)不可用的時(shí)間就越長佩憾;二是ClickHouse刪除分區(qū)的動(dòng)作,是在接收到刪除指令之后內(nèi)異步執(zhí)行,執(zhí)行完成時(shí)間是未知的摘投。如果增量數(shù)據(jù)導(dǎo)入后,刪除指令也還在異步執(zhí)行中虹蓄,會導(dǎo)致增量數(shù)據(jù)也會被刪除犀呼。最新版的更新日志說已修復(fù)這個(gè)問題。
針對以上情況薇组,我們修改了增量數(shù)據(jù)的同步方案外臂。在增量數(shù)據(jù)從Hive同步到ClickHouse的臨時(shí)表之后,將正式表中數(shù)據(jù)反寫到臨時(shí)表中律胀,然后通過ReName方法切換正式表和臨時(shí)表宋光。
通過以上流程,基本可以保證用戶對數(shù)據(jù)的導(dǎo)入過程是無感知的炭菌。
3.2 - 數(shù)據(jù)導(dǎo)入過程的監(jiān)控與預(yù)警
由于數(shù)據(jù)量大罪佳,數(shù)據(jù)同步的語句經(jīng)常性超時(shí)。為保證數(shù)據(jù)同步的每一個(gè)過程都是可監(jiān)控的黑低,我們沒有使用ClickHouse提供的JDBC來執(zhí)行數(shù)據(jù)同步語句赘艳,所有的數(shù)據(jù)同步語句都是通過調(diào)用ClickHouse的RestfulAPI來實(shí)現(xiàn)的。
調(diào)用RestfulAPI的時(shí)候,可以指定本次查詢的QueryID蕾管。在數(shù)據(jù)同步語句超時(shí)的情況下枷踏,通過輪詢來獲得某QueryID的執(zhí)行進(jìn)度。這樣保證了整個(gè)查詢過程的有序運(yùn)行掰曾。在輪詢的過程中旭蠕,會對異常情況進(jìn)行記錄,如果異常情況出現(xiàn)的頻次超過閾值婴梧,JOB會通過短信給相關(guān)人員發(fā)出預(yù)警短信下梢。
3.3 - 服務(wù)器分布與運(yùn)維
現(xiàn)在主要根據(jù)場景分國內(nèi),海外/供應(yīng)商塞蹭,實(shí)時(shí)數(shù)據(jù)孽江,風(fēng)控?cái)?shù)據(jù)4個(gè)集群。每個(gè)集群對應(yīng)的兩到三臺服務(wù)器番电,相互之間做主備岗屏,程序內(nèi)部將查詢請求分散到不同的服務(wù)器上做負(fù)載均衡。
假如某一臺服務(wù)器出現(xiàn)故障漱办,通過配置界面修改某個(gè)集群的服務(wù)器節(jié)點(diǎn)这刷,該集群的請求就不會落到有故障的服務(wù)器上。如果在某個(gè)時(shí)間段某個(gè)特定的數(shù)據(jù)查詢量比較大娩井,組建虛擬集群暇屋,將所有的請求分散到其他資源富于的物理集群上。
下半年計(jì)劃把每個(gè)集群的兩臺機(jī)器分散到不同的機(jī)房洞辣,可以繼續(xù)起到現(xiàn)有的主備咐刨,負(fù)載均衡的作用還能起到dr的作用。同時(shí)為了保障線上應(yīng)用的高可用扬霜,我們會實(shí)現(xiàn)自動(dòng)健康檢測機(jī)制定鸟,針對突發(fā)異常的服務(wù)器自動(dòng)拉出我們的虛擬集群。
我們會監(jiān)控每臺服務(wù)器每天的查詢量著瓶,每個(gè)語句的執(zhí)行時(shí)間联予,服務(wù)器CPU,內(nèi)存相關(guān)指標(biāo)材原,以便于及時(shí)調(diào)整服務(wù)器上查詢量比較高的請求到其他服務(wù)器沸久。
4 - ClickHouse使用探索
我們在使用ClickHouse的過程中遇到過各種各樣的問題,總結(jié)出來供大家參考余蟹。
關(guān)閉Linux虛擬內(nèi)存麦向。在一次ClickHouse服務(wù)器內(nèi)存耗盡的情況下,我們Kill掉占用內(nèi)存最多的Query之后發(fā)現(xiàn)客叉,這臺ClickHouse服務(wù)器并沒有如預(yù)期的那樣恢復(fù)正常诵竭,所有的查詢依然運(yùn)行的十分緩慢话告。通過查看服務(wù)器的各項(xiàng)指標(biāo),發(fā)現(xiàn)虛擬內(nèi)存占用量異常卵慰。因?yàn)榇嬖诖罅康奈锢韮?nèi)存和虛擬內(nèi)存的數(shù)據(jù)交換沙郭,導(dǎo)致查詢速度十分緩慢。關(guān)閉虛擬內(nèi)存裳朋,并重啟服務(wù)后病线,應(yīng)用恢復(fù)正常。
為每一個(gè)賬戶添加join_use_nulls配置鲤嫡。ClickHouse的SQL語法是非標(biāo)準(zhǔn)的送挑,默認(rèn)情況下,以Left Join為例暖眼,如果左表中的一條記錄在右表中不存在惕耕,右表的相應(yīng)字段會返回該字段相應(yīng)數(shù)據(jù)類型的默認(rèn)值,而不是標(biāo)準(zhǔn)SQL中的Null值诫肠。對于習(xí)慣了標(biāo)準(zhǔn)SQL的我們來說司澎,這種返回值經(jīng)常會造成困擾。
JOIN操作時(shí)一定要把數(shù)據(jù)量小的表放在右邊栋豫,ClickHouse中無論是Left Join 挤安、Right Join還是Inner Join永遠(yuǎn)都是拿著右表中的每一條記錄到左表中查找該記錄是否存在,所以右表必須是小表丧鸯。
通過ClickHouse官方的JDBC向ClickHouse中批量寫入數(shù)據(jù)時(shí)蛤铜,必須控制每個(gè)批次的數(shù)據(jù)中涉及到的分區(qū)的數(shù)量,在寫入之前最好通過Order By語句對需要導(dǎo)入的數(shù)據(jù)進(jìn)行排序丛肢。無序的數(shù)據(jù)或者數(shù)據(jù)中涉及的分區(qū)太多昂羡,會導(dǎo)致ClickHouse無法及時(shí)的對新導(dǎo)入的數(shù)據(jù)進(jìn)行合并,從而影響查詢性能摔踱。
盡量減少JOIN時(shí)的左右表的數(shù)據(jù)量,必要時(shí)可以提前對某張表進(jìn)行聚合操作怨愤,減少數(shù)據(jù)條數(shù)派敷。有些時(shí)候,先GROUP BY再JOIN比先JOIN再GROUP BY查詢時(shí)間更短撰洗。
ClickHouse版本迭代很快篮愉,建議用去年的穩(wěn)定版,不能太激進(jìn)差导,新版本我們在使用過程中遇到過一些bug试躏,內(nèi)存泄漏,語法不兼容但也不報(bào)錯(cuò)设褐,配置文件并發(fā)數(shù)修改后無法生效等問題颠蕴。
避免使用分布式表泣刹,ClickHouse的分布式表性能上性價(jià)比不如物理表高,建表分區(qū)字段值不宜過多犀被,太多的分區(qū)數(shù)據(jù)導(dǎo)入過程磁盤可能會被打滿椅您。
服務(wù)器CPU一般在50%左右會出現(xiàn)查詢波動(dòng),CPU達(dá)到70%會出現(xiàn)大范圍的查詢超時(shí)寡键,所以ClickHouse最關(guān)鍵的指標(biāo)CPU要非常關(guān)注掀泳。我們內(nèi)部對所有ClickHouse查詢都有監(jiān)控,當(dāng)出現(xiàn)查詢波動(dòng)的時(shí)候會有郵件預(yù)警西轩。
查詢測試Case有:6000W數(shù)據(jù)關(guān)聯(lián)1000W數(shù)據(jù)再關(guān)聯(lián)2000W數(shù)據(jù)sum一個(gè)月間夜量返回結(jié)果:190ms员舵;2.4億數(shù)據(jù)關(guān)聯(lián)2000W的數(shù)據(jù)group by一個(gè)月的數(shù)據(jù)大概390ms。但ClickHouse并非無所不能藕畔,查詢語句需要不斷的調(diào)優(yōu)马僻,可能與查詢條件有關(guān),不同的查詢條件表是左join還是右join也是很有講究的劫流。
5 - 總結(jié)
酒店數(shù)據(jù)智能平臺從去年7月份試點(diǎn)巫玻,到現(xiàn)在80%以上的業(yè)務(wù)都已接入ClickHouse。滿足每天十多億的數(shù)據(jù)更新和近百萬次的數(shù)據(jù)查詢祠汇,支撐app性能98.3%在1秒內(nèi)返回結(jié)果仍秤,pc端98.5%在3秒內(nèi)返回結(jié)果。
從使用的角度可很,查詢性能不是數(shù)據(jù)庫能相比的诗力,從成本上也是遠(yuǎn)低于關(guān)系型數(shù)據(jù)庫成本的,單機(jī)支撐40億以上的數(shù)據(jù)查詢毫無壓力我抠。與ElasticSearch苇本,Redis相比ClickHouse可以滿足我們大部分使用場景。
我們會繼續(xù)更深入的研究ClickHouse菜拓,跟進(jìn)最新的版本瓣窄,同時(shí)也會繼續(xù)保持對外界更好的開源框架的研究,嘗試纳鼎,尋找到更合適我們的技術(shù)框架俺夕。