【轉(zhuǎn)】每天十億級(jí)數(shù)據(jù)更新,秒出查詢(xún)結(jié)果,ClickHouse在攜程酒店的應(yīng)用

本文轉(zhuǎn)自 | 攜程技術(shù)中心 作者 | 蔡岳毅

作者簡(jiǎn)介:
蔡岳毅,攜程酒店大數(shù)據(jù)高級(jí)研發(fā)經(jīng)理,負(fù)責(zé)酒店數(shù)據(jù)智能平臺(tái)研發(fā),大數(shù)據(jù)技術(shù)創(chuàng)新工作。喜歡探索研究大數(shù)據(jù)的開(kāi)源技術(shù)框架。

1 - 背景

  • 攜程酒店每天有上千表,累計(jì)十多億數(shù)據(jù)更新,如何保證數(shù)據(jù)更新過(guò)程中生產(chǎn)應(yīng)用高可用;
  • 每天有將近百萬(wàn)次數(shù)據(jù)查詢(xún)請(qǐng)求,用戶(hù)可以從粗粒度國(guó)家省份城市匯總不斷下鉆到酒店,房型粒度的數(shù)據(jù),我們往往無(wú)法對(duì)海量的明細(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ù)用戶(hù)場(chǎng)景獲取不同維度的匯總數(shù)據(jù);
  • 為了讓用戶(hù)無(wú)論在app端還是pc端查詢(xún)數(shù)據(jù)提供秒出的效果,我們需要不斷的探索,研究找到最合適的技術(shù)框架;

對(duì)此,我們嘗試過(guò)關(guān)系型數(shù)據(jù)庫(kù),但千萬(wàn)級(jí)表關(guān)聯(lián)數(shù)據(jù)庫(kù)基本上不太可能做到秒出,考慮過(guò)Sharding,但數(shù)據(jù)量大,各種成本都很高。熱數(shù)據(jù)存儲(chǔ)到ElasticSearch,但無(wú)法跨索引關(guān)聯(lián),導(dǎo)致不得不做寬表,因?yàn)闄?quán)限,酒店信息會(huì)變,所以每次要刷全量數(shù)據(jù),不適用于大表更新,維護(hù)成本也很高。Redis鍵值對(duì)存儲(chǔ)無(wú)法做到實(shí)時(shí)匯總,也測(cè)試過(guò)Presto,GreenPlum,kylin,真正讓我們停下來(lái)深入研究,不斷的擴(kuò)展使用場(chǎng)景的是ClickHouse。

2 - ClickHouse介紹

ClickHouse是一款用于大數(shù)據(jù)實(shí)時(shí)分析的列式數(shù)據(jù)庫(kù)管理系統(tǒng),而非數(shù)據(jù)庫(kù)。通過(guò)向量化執(zhí)行以及對(duì)cpu底層指令集(SIMD)的使用,它可以對(duì)海量數(shù)據(jù)進(jìn)行并行處理,從而加快數(shù)據(jù)的處理速度。

主要優(yōu)點(diǎn)有:

  1. 為了高效的使用CPU,數(shù)據(jù)不僅僅按列存儲(chǔ),同時(shí)還按向量進(jìn)行處理;
  2. 數(shù)據(jù)壓縮空間大,減少io;處理單查詢(xún)高吞吐量每臺(tái)服務(wù)器每秒最多數(shù)十億行;
  3. 索引非B樹(shù)結(jié)構(gòu),不需要滿(mǎn)足最左原則;只要過(guò)濾條件在索引列中包含即可;即使在使用的數(shù)據(jù)不在索引中,由于各種并行處理機(jī)制ClickHouse全表掃描的速度也很快;
  4. 寫(xiě)入速度非常快,50-200M/s,對(duì)于大量的數(shù)據(jù)更新非常適用;

ClickHouse并非萬(wàn)能的,正因?yàn)镃lickHouse處理速度快,所以也是需要為“快”付出代價(jià)。選擇ClickHouse需要有下面注意以下幾點(diǎn):

  1. 不支持事務(wù),不支持真正的刪除/更新;
  2. 不支持高并發(fā),官方建議qps為100,可以通過(guò)修改配置文件增加連接數(shù),但是在服務(wù)器足夠好的情況下;
  3. sql滿(mǎn)足日常使用80%以上的語(yǔ)法,join寫(xiě)法比較特殊;最新版已支持類(lèi)似sql的join,但性能不好;
  4. 盡量做1000條以上批量的寫(xiě)入,避免逐行insert或小批量的insert,update,delete操作,因?yàn)镃lickHouse底層會(huì)不斷的做異步的數(shù)據(jù)合并,會(huì)影響查詢(xún)性能,這個(gè)在做實(shí)時(shí)數(shù)據(jù)寫(xiě)入的時(shí)候要盡量避開(kāi);
  5. Clickhouse快是因?yàn)椴捎昧瞬⑿刑幚頇C(jī)制,即使一個(gè)查詢(xún),也會(huì)用服務(wù)器一半的cpu去執(zhí)行,所以ClickHouse不能支持高并發(fā)的使用場(chǎng)景,默認(rèn)單查詢(xún)使用cpu核數(shù)為服務(wù)器核數(shù)的一半,安裝時(shí)會(huì)自動(dòng)識(shí)別服務(wù)器核數(shù),可以通過(guò)配置文件修改該參數(shù);

3 - ClickHouse在酒店數(shù)據(jù)智能平臺(tái)的實(shí)踐

3.1 - 數(shù)據(jù)更新

我們的主要數(shù)據(jù)源是Hive到ClickHouse,現(xiàn)在主要采用如下兩種方式:

Hive到MySql,再導(dǎo)入到ClickHouse
初期在DataX不支持hive到ClickHouse的數(shù)據(jù)導(dǎo)入,我們是通過(guò)DataX將數(shù)據(jù)先導(dǎo)入mysql,再通過(guò)ClickHouse原生api將數(shù)據(jù)從mysql導(dǎo)入到ClickHouse。

為此我們?cè)O(shè)計(jì)了一套完整的數(shù)據(jù)導(dǎo)入流程,保證數(shù)據(jù)從hive到mysql再到ClickHouse能自動(dòng)化,穩(wěn)定的運(yùn)行,并保證數(shù)據(jù)在同步過(guò)程中線(xiàn)上應(yīng)用的高可用。


數(shù)據(jù)導(dǎo)入流程

Hive到ClickHouse
DataX現(xiàn)在支持hive到ClickHouse,我們部分?jǐn)?shù)據(jù)是通過(guò)DataX直接導(dǎo)入ClickHouse。但DataX暫時(shí)只支持導(dǎo)入,因?yàn)橐WC線(xiàn)上的高可用,所以?xún)H僅導(dǎo)入是不夠的,還需要繼續(xù)依賴(lài)我們上面的一套流程來(lái)做ReName,增量數(shù)據(jù)更新等操作。

針對(duì)數(shù)據(jù)高可用,我們對(duì)數(shù)據(jù)更新機(jī)制做了如下設(shè)計(jì):
全量數(shù)據(jù)導(dǎo)入流程

全量數(shù)據(jù)導(dǎo)入流程

全量數(shù)據(jù)的導(dǎo)入過(guò)程比較簡(jiǎn)單,僅需要將數(shù)據(jù)先導(dǎo)入到臨時(shí)表中,導(dǎo)入完成之后,再通過(guò)對(duì)正式表和臨時(shí)表進(jìn)行ReName操作,將對(duì)數(shù)據(jù)的讀取從老數(shù)據(jù)切換到新數(shù)據(jù)上來(lái)。

增量數(shù)據(jù)的導(dǎo)入過(guò)程

增量數(shù)據(jù)導(dǎo)入流程

增量數(shù)據(jù)的導(dǎo)入過(guò)程,我們使用過(guò)兩個(gè)版本。

由于ClickHouse的delete操作過(guò)于沉重,所以最早是通過(guò)刪除指定分區(qū),再把增量數(shù)據(jù)導(dǎo)入正式表的方式來(lái)實(shí)現(xiàn)的。

這種方式存在如下問(wèn)題:一是在增量數(shù)據(jù)導(dǎo)入的過(guò)程中,數(shù)據(jù)的準(zhǔn)確性是不可保證的,如果增量數(shù)據(jù)越多,數(shù)據(jù)不可用的時(shí)間就越長(zhǎng);二是ClickHouse刪除分區(qū)的動(dòng)作,是在接收到刪除指令之后內(nèi)異步執(zhí)行,執(zhí)行完成時(shí)間是未知的。如果增量數(shù)據(jù)導(dǎo)入后,刪除指令也還在異步執(zhí)行中,會(huì)導(dǎo)致增量數(shù)據(jù)也會(huì)被刪除。最新版的更新日志說(shuō)已修復(fù)這個(gè)問(wèn)題。

針對(duì)以上情況,我們修改了增量數(shù)據(jù)的同步方案。在增量數(shù)據(jù)從Hive同步到ClickHouse的臨時(shí)表之后,將正式表中數(shù)據(jù)反寫(xiě)到臨時(shí)表中,然后通過(guò)ReName方法切換正式表和臨時(shí)表。

通過(guò)以上流程,基本可以保證用戶(hù)對(duì)數(shù)據(jù)的導(dǎo)入過(guò)程是無(wú)感知的。

3.2 - 數(shù)據(jù)導(dǎo)入過(guò)程的監(jiān)控與預(yù)警

由于數(shù)據(jù)量大,數(shù)據(jù)同步的語(yǔ)句經(jīng)常性超時(shí)。為保證數(shù)據(jù)同步的每一個(gè)過(guò)程都是可監(jiān)控的,我們沒(méi)有使用ClickHouse提供的JDBC來(lái)執(zhí)行數(shù)據(jù)同步語(yǔ)句,所有的數(shù)據(jù)同步語(yǔ)句都是通過(guò)調(diào)用ClickHouse的RestfulAPI來(lái)實(shí)現(xiàn)的。

調(diào)用RestfulAPI的時(shí)候,可以指定本次查詢(xún)的QueryID。在數(shù)據(jù)同步語(yǔ)句超時(shí)的情況下,通過(guò)輪詢(xún)來(lái)獲得某QueryID的執(zhí)行進(jìn)度。這樣保證了整個(gè)查詢(xún)過(guò)程的有序運(yùn)行。在輪詢(xún)的過(guò)程中,會(huì)對(duì)異常情況進(jìn)行記錄,如果異常情況出現(xiàn)的頻次超過(guò)閾值,JOB會(huì)通過(guò)短信給相關(guān)人員發(fā)出預(yù)警短信。

3.3 - 服務(wù)器分布與運(yùn)維

現(xiàn)在主要根據(jù)場(chǎng)景分國(guó)內(nèi),海外/供應(yīng)商,實(shí)時(shí)數(shù)據(jù),風(fēng)控?cái)?shù)據(jù)4個(gè)集群。每個(gè)集群對(duì)應(yīng)的兩到三臺(tái)服務(wù)器,相互之間做主備,程序內(nèi)部將查詢(xún)請(qǐng)求分散到不同的服務(wù)器上做負(fù)載均衡。

假如某一臺(tái)服務(wù)器出現(xiàn)故障,通過(guò)配置界面修改某個(gè)集群的服務(wù)器節(jié)點(diǎn),該集群的請(qǐng)求就不會(huì)落到有故障的服務(wù)器上。如果在某個(gè)時(shí)間段某個(gè)特定的數(shù)據(jù)查詢(xún)量比較大,組建虛擬集群,將所有的請(qǐng)求分散到其他資源富于的物理集群上。

下半年計(jì)劃把每個(gè)集群的兩臺(tái)機(jī)器分散到不同的機(jī)房,可以繼續(xù)起到現(xiàn)有的主備,負(fù)載均衡的作用還能起到dr的作用。同時(shí)為了保障線(xiàn)上應(yīng)用的高可用,我們會(huì)實(shí)現(xiàn)自動(dòng)健康檢測(cè)機(jī)制,針對(duì)突發(fā)異常的服務(wù)器自動(dòng)拉出我們的虛擬集群。

我們會(huì)監(jiān)控每臺(tái)服務(wù)器每天的查詢(xún)量,每個(gè)語(yǔ)句的執(zhí)行時(shí)間,服務(wù)器CPU,內(nèi)存相關(guān)指標(biāo),以便于及時(shí)調(diào)整服務(wù)器上查詢(xún)量比較高的請(qǐng)求到其他服務(wù)器。

4 - ClickHouse使用探索

我們?cè)谑褂肅lickHouse的過(guò)程中遇到過(guò)各種各樣的問(wèn)題,總結(jié)出來(lái)供大家參考。

  • 關(guān)閉Linux虛擬內(nèi)存。在一次ClickHouse服務(wù)器內(nèi)存耗盡的情況下,我們Kill掉占用內(nèi)存最多的Query之后發(fā)現(xiàn),這臺(tái)ClickHouse服務(wù)器并沒(méi)有如預(yù)期的那樣恢復(fù)正常,所有的查詢(xún)依然運(yùn)行的十分緩慢。通過(guò)查看服務(wù)器的各項(xiàng)指標(biāo),發(fā)現(xiàn)虛擬內(nèi)存占用量異常。因?yàn)榇嬖诖罅康奈锢韮?nèi)存和虛擬內(nèi)存的數(shù)據(jù)交換,導(dǎo)致查詢(xún)速度十分緩慢。關(guān)閉虛擬內(nèi)存,并重啟服務(wù)后,應(yīng)用恢復(fù)正常。

  • 為每一個(gè)賬戶(hù)添加join_use_nulls配置。ClickHouse的SQL語(yǔ)法是非標(biāo)準(zhǔn)的,默認(rèn)情況下,以L(fǎng)eft Join為例,如果左表中的一條記錄在右表中不存在,右表的相應(yīng)字段會(huì)返回該字段相應(yīng)數(shù)據(jù)類(lèi)型的默認(rèn)值,而不是標(biāo)準(zhǔn)SQL中的Null值。對(duì)于習(xí)慣了標(biāo)準(zhǔn)SQL的我們來(lái)說(shuō),這種返回值經(jīng)常會(huì)造成困擾。

  • JOIN操作時(shí)一定要把數(shù)據(jù)量小的表放在右邊,ClickHouse中無(wú)論是Left Join 、Right Join還是Inner Join永遠(yuǎn)都是拿著右表中的每一條記錄到左表中查找該記錄是否存在,所以右表必須是小表。

  • 通過(guò)ClickHouse官方的JDBC向ClickHouse中批量寫(xiě)入數(shù)據(jù)時(shí),必須控制每個(gè)批次的數(shù)據(jù)中涉及到的分區(qū)的數(shù)量,在寫(xiě)入之前最好通過(guò)Order By語(yǔ)句對(duì)需要導(dǎo)入的數(shù)據(jù)進(jìn)行排序。無(wú)序的數(shù)據(jù)或者數(shù)據(jù)中涉及的分區(qū)太多,會(huì)導(dǎo)致ClickHouse無(wú)法及時(shí)的對(duì)新導(dǎo)入的數(shù)據(jù)進(jìn)行合并,從而影響查詢(xún)性能。

  • 盡量減少JOIN時(shí)的左右表的數(shù)據(jù)量,必要時(shí)可以提前對(duì)某張表進(jìn)行聚合操作,減少數(shù)據(jù)條數(shù)。有些時(shí)候,先GROUP BY再JOIN比先JOIN再GROUP BY查詢(xún)時(shí)間更短。

  • ClickHouse版本迭代很快,建議用去年的穩(wěn)定版,不能太激進(jìn),新版本我們?cè)谑褂眠^(guò)程中遇到過(guò)一些bug,內(nèi)存泄漏,語(yǔ)法不兼容但也不報(bào)錯(cuò),配置文件并發(fā)數(shù)修改后無(wú)法生效等問(wèn)題。

  • 避免使用分布式表,ClickHouse的分布式表性能上性?xún)r(jià)比不如物理表高,建表分區(qū)字段值不宜過(guò)多,太多的分區(qū)數(shù)據(jù)導(dǎo)入過(guò)程磁盤(pán)可能會(huì)被打滿(mǎn)。

  • 服務(wù)器CPU一般在50%左右會(huì)出現(xiàn)查詢(xún)波動(dòng),CPU達(dá)到70%會(huì)出現(xiàn)大范圍的查詢(xún)超時(shí),所以ClickHouse最關(guān)鍵的指標(biāo)CPU要非常關(guān)注。我們內(nèi)部對(duì)所有ClickHouse查詢(xún)都有監(jiān)控,當(dāng)出現(xiàn)查詢(xún)波動(dòng)的時(shí)候會(huì)有郵件預(yù)警。

  • 查詢(xún)測(cè)試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并非無(wú)所不能,查詢(xún)語(yǔ)句需要不斷的調(diào)優(yōu),可能與查詢(xún)條件有關(guān),不同的查詢(xún)條件表是左join還是右join也是很有講究的。

5 - 總結(jié)

酒店數(shù)據(jù)智能平臺(tái)從去年7月份試點(diǎn),到現(xiàn)在80%以上的業(yè)務(wù)都已接入ClickHouse。滿(mǎn)足每天十多億的數(shù)據(jù)更新和近百萬(wàn)次的數(shù)據(jù)查詢(xún),支撐app性能98.3%在1秒內(nèi)返回結(jié)果,pc端98.5%在3秒內(nèi)返回結(jié)果。

從使用的角度,查詢(xún)性能不是數(shù)據(jù)庫(kù)能相比的,從成本上也是遠(yuǎn)低于關(guān)系型數(shù)據(jù)庫(kù)成本的,單機(jī)支撐40億以上的數(shù)據(jù)查詢(xún)毫無(wú)壓力。與ElasticSearch,Redis相比ClickHouse可以滿(mǎn)足我們大部分使用場(chǎng)景。

我們會(huì)繼續(xù)更深入的研究ClickHouse,跟進(jìn)最新的版本,同時(shí)也會(huì)繼續(xù)保持對(duì)外界更好的開(kāi)源框架的研究,嘗試,尋找到更合適我們的技術(shù)框架。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,637評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,555評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,900評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,629評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,976評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評(píng)論 3 448
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,139評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,686評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,411評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,641評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,820評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,233評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,567評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,362評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,604評(píng)論 2 380

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