關(guān)注我,回復(fù)"資料",獲取精美的大數(shù)據(jù)資料
- 前言 -
Hadoop生態(tài)圈的技術(shù)繁多。HDFS一直用來保存底層數(shù)據(jù),地位牢固。Hbase作為一款Nosql也是Hadoop生態(tài)圈的核心組件,它海量的存儲能力,優(yōu)秀的隨機讀寫能力,能夠處理一些HDFS不足的地方。Clickhouse是一個用于聯(lián)機分析(OLAP)的列式數(shù)據(jù)庫管理系統(tǒng)(DBMS)。能夠使用SQL查詢實時生成分析數(shù)據(jù)報告。它同樣擁有優(yōu)秀的數(shù)據(jù)存儲能力。Apache Kudu是Cloudera Manager公司16年發(fā)布的新型分布式存儲系統(tǒng),結(jié)合CDH和Impala使用可以同時解決隨機讀寫和sql化數(shù)據(jù)分析的問題。分別彌補HDFS靜態(tài)存儲和Hbase Nosql的不足。既然可選的技術(shù)路線有這么多,本文將從安裝部署、架構(gòu)組成、基本操作等方面橫向?qū)Ρ纫幌翲base、Kudu和Clickhouse。另外這里還引入了幾個大廠的實踐作為例子予以參考。
- 安裝部署方式對比 -
具體的安裝步驟不過多贅述,這里只簡要比較安裝過程中需要依賴的外部組件。

- Habse 安裝 -
依賴HDFS作為底層存儲插件 依賴Zookeeper作為元數(shù)據(jù)存儲插件。
- Kudu 安裝 -
依賴Impala作為輔助分析插件 依賴CDH集群作為管理插件,但是不是必選的,也可以單獨安裝。
- ClickHouse 安裝 -
依賴Zookeeper作為元數(shù)據(jù)存儲插件和Log Service以及表的 catalog service組成架構(gòu)對比。




綜上所示,Hbase和Kudu都是類似于Master-slave的架構(gòu)而Clickhouse不存在Master結(jié)構(gòu),Clickhouse的每臺Server的地位都是等價的,是multi-master模式。不過Hbase和Clickhouse額外增加了一個Zookeeper作為輔助的元數(shù)據(jù)存儲或者是log server等,而Kudu的元數(shù)據(jù)是Master管理的,為了避免server頻繁從Master讀取元數(shù)據(jù),server會從Master獲取一份元數(shù)據(jù)到本地,但是會有元數(shù)據(jù)丟失的風(fēng)險。
- 基本操作對比 -
數(shù)據(jù)讀寫操作



Clickhouse是個分析型數(shù)據(jù)庫。這種場景下,數(shù)據(jù)一般是不變的,因此Clickhouse對update、delete的支持是比較弱的,實際上并不支持標準的update、delete操作。Clickhouse通過alter方式實現(xiàn)更新、刪除,它把update、delete操作叫做mutation(突變)。標準SQL的更新、刪除操作是同步的,即客戶端要等服務(wù)端反回執(zhí)行結(jié)果(通常是int值);而Clickhouse的update、delete是通過異步方式實現(xiàn)的,當執(zhí)行update語句時,服務(wù)端立即反回,但是實際上此時數(shù)據(jù)還沒變,而是排隊等著。首先,使用where條件找到需要修改的分區(qū);然后,重建每個分區(qū),用新的分區(qū)替換舊的,分區(qū)一旦被替換,就不可回退;對于每個分區(qū),可以認為是原子性的;但對于整個mutation,如果涉及多個分區(qū),則不是原子性的。?更新功能不支持更新有關(guān)主鍵或分區(qū)鍵的列;?更新操作沒有原子性,即在更新過程中select結(jié)果很可能是一部分變了,一部分沒變,從上邊的具體過程就可以知道;?更新一旦提交,不能撤銷,即使重啟Clickhouse服務(wù),也會繼續(xù)按照system.mutations的順序繼續(xù)執(zhí)行;?已完成更新的條目不會立即刪除,保留條目的數(shù)量由finished_mutations_to_keep存儲引擎參數(shù)確定。超過數(shù)據(jù)量時舊的條目會被刪除;?更新可能會卡住,比如update intvalue='abc’這種類型錯誤的更新語句執(zhí)行不過去,那么會一直卡在這里,此時,可以使用KILL MUTATION來取消。綜上所示,Hbase隨機讀寫,但是Hbase的update操作不是真的update,它的實際操作是insert一條新的數(shù)據(jù),打上不同的timestamp,而老的數(shù)據(jù)會在有效期之后自動刪除。而Clickhouse干脆就不支持update和delete。
- 數(shù)據(jù)查詢操作 -
不支持標準sql,需要集成Phoenix插件。Hbase自身有Scan操作,但是不建議執(zhí)行,一般會全量掃描導(dǎo)致集群崩潰。HBASE在滴滴出行的應(yīng)用場景和最佳實踐
HBase在滴滴主要存放了以下四種數(shù)據(jù)類型:?統(tǒng)計結(jié)果、報表類數(shù)據(jù):主要是運營、運力情況、收入等結(jié)果,通常需要配合Phoenix進行SQL查詢。數(shù)據(jù)量較小,對查詢的靈活性要求高,延遲要求一般。?原始事實類數(shù)據(jù):如訂單、司機乘客的GPS軌跡、日志等,主要用作在線和離線的數(shù)據(jù)供給。數(shù)據(jù)量大,對一致性和可用性要求高,延遲敏感,實時寫入,單點或批量查詢。?中間結(jié)果數(shù)據(jù):指模型訓(xùn)練所需要的數(shù)據(jù)等。數(shù)據(jù)量大,可用性和一致性要求一般,對批量查詢時的吞吐量要求高。?線上系統(tǒng)的備份數(shù)據(jù):用戶把原始數(shù)據(jù)存在了其他關(guān)系數(shù)據(jù)庫或文件服務(wù),把HBase作為一個異地容災(zāi)的方案。
- 訂單事件 -
近期訂單的查詢會落在Redis,超過一定時間范圍,或者當Redis不可用時,查詢會落在HBase上。業(yè)務(wù)方的需求如下:?在線查詢訂單生命周期的各個狀態(tài),包括status、event_type、order_detail等信息。主要的查詢來自于客服系統(tǒng);?在線歷史訂單詳情查詢。上層會有Redis來存儲近期的訂單,當Redis不可用或者查詢范圍超出Redis,查詢會直接落到HBase;?離線對訂單的狀態(tài)進行分析?寫入滿足每秒10K的事件,讀取滿足每秒1K的事件,數(shù)據(jù)要求在5s內(nèi)可用。
按照這些要求,我們對Rowkey做出了下面的設(shè)計,都是很典型的scan場景。Rowkey:reverse(order_id) + (MAX_LONG - TS)Rowkey:reverse(passenger_id | driver_id) + (MAX_LONG - TS)Columns:用戶在時間范圍內(nèi)的訂單及其他信息。
- 司機乘客軌跡 -
舉幾個使用場景上的例子:用戶查看歷史訂單時,地圖上顯示所經(jīng)過的路線;發(fā)生司乘糾紛,客服調(diào)用訂單軌跡復(fù)現(xiàn)場景;地圖部門用戶分析道路擁堵情況。
?滿足App用戶或者后端分析人員的實時或準實時軌跡坐標查詢;?滿足給出一個指定的地理范圍,取出范圍內(nèi)所有用戶的軌跡或范圍內(nèi)出現(xiàn)過的用戶。其中,關(guān)于第三個需求,地理位置查詢,我們知道MongoDB對于這種地理索引有源生的支持,但是在滴滴這種量級的情況下可能會發(fā)生存儲瓶頸,HBase存儲和擴展性上沒有壓力但是沒有內(nèi)置類似MongoDB地理位置索引的功能,沒有就需要我們自己實現(xiàn)。通過調(diào)研,了解到關(guān)于地理索引有一套比較通用的GeohHash算法 。把GeoHash和其他一些需要被索引的維度拼裝成Rowkey,真實的GPS點為Value,在這個基礎(chǔ)上封裝成客戶端,并且在客戶端內(nèi)部對查詢邏輯和查詢策略做出速度上的大幅優(yōu)化,這樣就把HBase變成了一個MongoDB一樣支持地理位置索引的數(shù)據(jù)庫。如果查詢范圍非常大(比如進行省級別的分析),還額外提供了MR的獲取數(shù)據(jù)的入口。?單個用戶按訂單或時間段查詢:reverse(user_id) + (Integer.MAX_LONG-TS/1000);?給定范圍內(nèi)的軌跡查詢:reverse(geohash) + ts/1000 + user_id。

- ETA -
ETA是指每次選好起始和目的地后,提示出的預(yù)估時間和價格。提示的預(yù)估到達時間和價格,最初版本是離線方式運行,后來改版通過HBase實現(xiàn)實時效果,把HBase當成一個KeyValue緩存,帶來了減少訓(xùn)練時間、可多城市并行、減少人工干預(yù)的好處。整個ETA的過程如下:1.模型訓(xùn)練通過Spark Job,每30分鐘對各個城市訓(xùn)練一次;2.模型訓(xùn)練第一階段,在5分鐘內(nèi),按照設(shè)定條件從HBase讀取所有城市數(shù)據(jù);3.模型訓(xùn)練第二階段在25分鐘內(nèi)完成ETA的計算;4.HBase中的數(shù)據(jù)每隔一段時間會持久化至HDFS中,供新模型測試和新的特征提取。Rowkey:salting+cited+type0+type1+type2+TS Column:order, feature

- 監(jiān)控工具 DCM -
用于監(jiān)控Hadoop集群的資源使用(Namenode,Yarn container使用等),關(guān)系數(shù)據(jù)庫在時間維度過程以后會產(chǎn)生各種性能問題,同時我們又希望可以通過SQL做一些分析查詢,所以使用Phoenix,使用采集程序定時錄入數(shù)據(jù),生產(chǎn)成報表,存入HBase,可以在秒級別返回查詢結(jié)果,最后在前端做展示:

- 小結(jié) -
在滴滴推廣和實踐HBase的工作中,我們認為至關(guān)重要的兩點是幫助用戶做出良好的表結(jié)構(gòu)設(shè)計和資源的控制。有了這兩個前提之后,后續(xù)出現(xiàn)問題的概率會大大降低。良好的表結(jié)構(gòu)設(shè)計需要用戶對HBase的實現(xiàn)有一個清晰的認識,大多數(shù)業(yè)務(wù)用戶把更多精力放在了業(yè)務(wù)邏輯上,對架構(gòu)實現(xiàn)知之甚少,這就需要平臺管理者去不斷幫助和引導(dǎo),有了好的開端和成功案例后,通過這些用戶再去向其他的業(yè)務(wù)方推廣。
資源隔離控制則幫助我們有效減少集群的數(shù)量,降低運維成本,讓平臺管理者從多集群無止盡的管理工作中解放出來,將更多精力投入到組件社區(qū)跟進和平臺管理系統(tǒng)的研發(fā)工作中,使業(yè)務(wù)和平臺都進入一個良性循環(huán),提升用戶的使用體驗,更好地支持公司業(yè)務(wù)的發(fā)展。網(wǎng)易考拉基于KUDU構(gòu)建實時流量數(shù)倉實踐
Kudu不但提供了行級的插入、更新、刪除API,同時也提供了接近Parquet性能的批量掃描操作。使用同一份存儲,既可以進行隨機讀寫,也可以滿足數(shù)據(jù)分析的要求。實時流/業(yè)務(wù)數(shù)據(jù)寫入
可以使用Spark Streaming 提供的KafkaUtils.createDirectStream方法來創(chuàng)建一個對應(yīng)topic的Dstream。這種方法topic的offset將完全由我們自己控制:private val stream = KafkaUtils.createDirectStream[String, String](
ssc,
PreferConsistent,
Subscribe[String, String](topics, kafkaParams)
)
?按照解析邏輯解析流量日志并構(gòu)建DataFrameval offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
val spark = SparkSession.builder.config(rdd.sparkContext.getConf).getOrCreate()
val kuduContext = new KuduContext(kuduMaster, spark.sparkContext)
val flowDf = spark.createDataFrame(rdd.map(r => {
processFlowLine(r.value)
}).filter(row => if (row.get(0) == null) false else true), schema)
kuduContext.upsertRows(flowDf, "impala::kaola_kudu_internal.dwd_kl_flw_app_rt")
stream.asInstanceOf[CanCommitOffsets].commitAsync(offsetRanges)

- 寫入性能測試 -
Kudu寫入表: haitao_dev_log.dwd_kl_flw_app_rt,分片: 240個,Spark Streaming調(diào)度間隔: 15s。

可以發(fā)現(xiàn)75%的任務(wù)都在1s完成,有少數(shù)任務(wù)跑的較慢但整體在2s都跑完了,這里需要注意一種極端情況,由于Spark的默認配置并發(fā)數(shù)是1,如果有一個進程遲遲沒有跑完(一般是數(shù)據(jù)分布不均)那么后面的任務(wù)將會排隊,直到最初的任務(wù)跑完才會去調(diào)度下一個任務(wù)。這樣會造成資源浪費,多個空閑的executor會一直等待最后一個executor,流量日志不要求順序插入,因此我們可以加大任務(wù)的并發(fā)數(shù)。具體參數(shù)設(shè)置:spark.streaming.concurrentJobs = N

- 小結(jié) -
目前實時寫入Kudu的流量日志在每日數(shù)十億條,寫入量在TB級,而且已有實時流量拆解等業(yè)務(wù)依賴Kudu的底層流量數(shù)據(jù),接下來將會有更多的業(yè)務(wù)線遷移至Kudu以滿足不同維度下的分析需求。攜程CLICKHOUSE日志分析實踐
結(jié)合攜程的日志分析場景,日志進入ES前已經(jīng)格式化成JSON,同一類日志有統(tǒng)一的Schema,符合ClickHouse Table的模式;日志查詢的時候,一般按照某一維度統(tǒng)計數(shù)量、總量、均值等,符合ClickHouse面向列式存儲的使用場景。偶爾有少量的場景需要對字符串進行模糊查詢,也是先經(jīng)過一些條件過濾掉大量數(shù)據(jù)后,再對少量數(shù)據(jù)進行模糊匹配,ClickHouse也能很好的勝任。另外我們發(fā)現(xiàn)90%以上的日志沒有使用ES的全文索引特性,因此我們決定嘗試用ClickHouse來處理日志。消費數(shù)據(jù)到CLICKHOUSE

我們使用gohangout消費數(shù)據(jù)到ClickHouse,關(guān)于數(shù)據(jù)寫入的幾點建議:?采用輪詢的方式寫ClickHouse集群的所有服務(wù)器,保證數(shù)據(jù)基本均勻分布。?大批次低頻率的寫入,減少parts數(shù)量,減少服務(wù)器merge,避免Too many parts異常。通過兩個閾值控制數(shù)據(jù)的寫入量和頻次,超過10w記錄寫一次或者30s寫一次。?寫本地表,不要寫分布式表,因為分布式表接收到數(shù)據(jù)后會將數(shù)據(jù)拆分成多個parts,并轉(zhuǎn)發(fā)數(shù)據(jù)到其它服務(wù)器,會引起服務(wù)器間網(wǎng)絡(luò)流量增加、服務(wù)器merge的工作量增加,導(dǎo)致寫入速度變慢,并且增加了Too many parts的可能性。
?建表時考慮partition的設(shè)置,之前遇到過有人將partition設(shè)置為timestamp,導(dǎo)致插入數(shù)據(jù)一直報Too many parts的異常。我們一般按天分partition。?主鍵和索引的設(shè)置、數(shù)據(jù)的亂序等也會導(dǎo)致寫入變慢。
- 數(shù)據(jù)展示 -
我們調(diào)研了像Supperset、Metabase、Grafana等幾個工具,最終還是決定采用在Kibana3上開發(fā)支持ClickHouse實現(xiàn)圖表展示。主要原因是Kibana3這種強大的數(shù)據(jù)過濾功能,很多系統(tǒng)都不具備,另外也考慮到遷移到其他系統(tǒng)成本較高,用戶短期內(nèi)難以適應(yīng)。
- 查詢優(yōu)化 -
Kibana中的Table Panel用于顯示日志的明細數(shù)據(jù),一般查詢最近1小時所有字段的數(shù)據(jù),最終只展示前500條記錄。這種場景對于ClickHouse來說非常不友好。針對這個問題,我們將table Panel的查詢分兩次進行:第一次查詢單位時間間隔的數(shù)據(jù)量,根據(jù)最終顯示的數(shù)據(jù)量計算出合理查詢的時間范圍;第二次根據(jù)修正后的時間范圍,結(jié)合Table Panel中配置的默認顯示的Column查詢明細數(shù)據(jù)。經(jīng)過這些優(yōu)化,查詢的時間可以縮短到原來的1/60,查詢的列可以減少50%,最終查詢數(shù)據(jù)量減少到原來的1/120;ClickHouse提供了多種近似計算的方法,用于提供相對較高準確性的同時減少計算量;使用MATERIALIZED VIEW或者MATERIALIZED COLUMN將計算量放在平常完成,也能有效降低查詢的數(shù)據(jù)量和計算量。
- ClickHouse 基本運維 -
總體來說ClickHouse的運維比ES簡單,主要包括以下幾個方面的工作:?過期日志的清理,我們通過一個定時任務(wù)每天刪除過期日志的partition;?ClickHouse的監(jiān)控,使用ClickHouse-exporter+VictoriaMetrics+Grafana的實現(xiàn);?數(shù)據(jù)遷移,通過ClickHouse分布式表的特性我們一般不搬遷歷史數(shù)據(jù),只要將新的數(shù)據(jù)接入新集群,然后通過分布式表跨集群查詢。隨著時間的推移,歷史數(shù)據(jù)會被清理下線,當老集群數(shù)據(jù)全部下線后,新老集群的遷移就完成了。確實需要遷移數(shù)據(jù)時,采用ClickHouse_copier或者復(fù)制數(shù)據(jù)的方式實現(xiàn)。慢查詢,通過kill query終止慢查詢的執(zhí)行,并通過前面提到的優(yōu)化方案進行優(yōu)化
Too many parts異常:Too many parts異常是由于寫入的part過多part的merge速度跟不上產(chǎn)生的速度,導(dǎo)致part過多的原因主要包括幾個方面:
?小批量、高頻次寫ClickHouse?寫的是ClickHouse的分布式表?ClickHouse設(shè)置的merge線程數(shù)太少了? 無法啟動:之前遇到過ClickHouse無法啟動的問題,主要包括兩個方面:- 文件系統(tǒng)損壞,通過修復(fù)文件系統(tǒng)可以解決
- 某一個表的數(shù)據(jù)異常導(dǎo)致ClickHouse加載失敗,可以刪除異常數(shù)據(jù)后啟動,也可以把異常的文件搬到detached目錄,等ClickHouse起來后再attach文件恢復(fù)數(shù)據(jù)
將日志從ES遷移到ClickHouse可以節(jié)省更多的服務(wù)器資源,總體運維成本更低,而且提升了查詢速度,特別是當用戶在緊急排障的時候,這種查詢速度的成倍提升,對用戶的使用體驗有明顯的改善。但是ClickHouse畢竟不是ES,在很多業(yè)務(wù)場景中ES仍然不可替代;ClickHouse也不僅只能處理日志,進一步深入研究ClickHouse,讓ClickHouse在更多領(lǐng)域發(fā)揮更大的價值,是我們一直努力的方向。
- 總結(jié) -
首先說一下Hbase與Kudu,可以說是Kudu師承Hbase,架構(gòu)是類似的master-slave結(jié)構(gòu)。Hbase的物理模型是master和regionserver,regionserver存儲的是region,region里邊很有很多store,一個store對應(yīng)一個列簇,一個store中有一個memstore和多個storefile,store的底層是hfile,hfile是hadoop的二進制文件,其中HFile和HLog是Hbase兩大文件存儲格式,HFile用于存儲數(shù)據(jù),HLog保證可以寫入到HFile中。Kudu的物理模型是master和tserver,其中table根據(jù)hash和range分區(qū),分為多個tablet存儲到tserver中,tablet分為leader和follower,leader負責(zé)寫請求,follower負責(zé)讀請求,總結(jié)來說,一個ts可以服務(wù)多個tablet,一個tablet可以被多個ts服務(wù)(基于tablet的分區(qū),最低為2個分區(qū))。而Clickhouse的特點在于它號稱最快的查詢性能,雖然也能存儲數(shù)據(jù),但并不是他的強項,而且Clickhouse還不能update/delete數(shù)據(jù)。最后從下面幾個維度來對比一下Hbase、Kudu和Clickhouse。
所以Hbase更適合非結(jié)構(gòu)化的數(shù)據(jù)存儲;在既要求隨機讀寫又要求實時更新的場景,Kudu+Impala可以很好的勝任,當然再結(jié)合CDH就更好了,瓶頸并不在Kudu,而在Impala的Apache部署。如果只要求靜態(tài)數(shù)據(jù)的極速查詢能力,Clickhouse則更好。作者:super_chenzhou
來源:
https://blog.csdn.net/qq_37067752/article/details/107686978