實(shí)時(shí)湖倉(cāng)一體在騰訊的落地實(shí)踐
一、湖倉(cāng)一體技術(shù)誕生的背景和現(xiàn)狀
1.湖倉(cāng)的演進(jìn)
1)數(shù)據(jù)倉(cāng)庫(kù)(90s)
需要進(jìn)行數(shù)據(jù)處理的公司在湖倉(cāng)演進(jìn)的架構(gòu)選擇上都十分相似。起初,首選方式是數(shù)倉(cāng)架構(gòu),比如teradata 、greenplum或Oracle等。通常數(shù)據(jù)處理的流程是把一些業(yè)務(wù)數(shù)據(jù)庫(kù),如Transactional Database等,通過(guò)ETL的方式加載到Data Warehouse中,再在前端接入一些報(bào)表或者BI的工具去展示。
自Bill Inmon提出數(shù)倉(cāng)概念以來(lái),從90年代的美國(guó)到國(guó)內(nèi),數(shù)倉(cāng)架構(gòu)一直是一個(gè)比較經(jīng)典的架構(gòu),它可以高效處理結(jié)構(gòu)化的數(shù)據(jù),而且性能好、速度快。尤其是teradata,它是存算一體的架構(gòu)。
但是隨著業(yè)務(wù)類型增多,我們需要擴(kuò)展更多的業(yè)務(wù)場(chǎng)景,如數(shù)據(jù)科學(xué)或機(jī)器科學(xué)領(lǐng)域等。數(shù)據(jù)類型和數(shù)量也隨之增多,結(jié)構(gòu)化數(shù)據(jù)在互聯(lián)網(wǎng)領(lǐng)域只占很小的一部分,還有很多半結(jié)構(gòu)化、非結(jié)構(gòu)化的埋點(diǎn)日志和音視頻數(shù)據(jù)等。
我們的數(shù)倉(cāng)已經(jīng)無(wú)法處理更多數(shù)據(jù),一些新技術(shù),尤其是開(kāi)源等多個(gè)領(lǐng)域的大數(shù)據(jù)技術(shù)開(kāi)始涌現(xiàn)。
2)數(shù)據(jù)湖——數(shù)倉(cāng)兩層架構(gòu)(10s)
我們逐漸將架構(gòu)劃分為數(shù)倉(cāng)和數(shù)據(jù)庫(kù)的雙層架構(gòu),把數(shù)據(jù)先加載到數(shù)據(jù)湖中,通常我們會(huì)選擇Hadoop數(shù)據(jù)庫(kù)作為自建數(shù)據(jù)湖。如果要做高效的查詢或者報(bào)表的輸出,我們會(huì)對(duì)數(shù)據(jù)再加工,放入高性能的數(shù)倉(cāng)中,如ClickHouse或Doris等。
大概從2010年開(kāi)始,隨著Hadoop的盛行,絕大多數(shù)互聯(lián)網(wǎng)公司都在用這樣的架構(gòu)。大家如果使用過(guò)Hadoop,相信也能感知到它可以支持各種不同的場(chǎng)景,基本上能夠滿足所有業(yè)務(wù)場(chǎng)景。
缺點(diǎn):
- 在效率方面存在較大缺陷,比如數(shù)據(jù)要來(lái)回導(dǎo),以ETL或者反向ETL的方式導(dǎo)進(jìn)導(dǎo)出,會(huì)出現(xiàn)多份;
- 一致性很難保證。
3)倉(cāng)、湖、流——孤島式架構(gòu)(15s)
這個(gè)架構(gòu)整體偏離線處理,隨著流式框架的引入,大公司整體的數(shù)據(jù)處理架構(gòu)在2015年后就變成了倉(cāng)、湖、流三種架構(gòu)。
根據(jù)不同的場(chǎng)景選擇不同的架構(gòu),比如我要做一些Ad-hoc的場(chǎng)景,我們會(huì)選擇在倉(cāng)里面進(jìn)行;如果要做一些定時(shí)的報(bào)表或業(yè)務(wù)報(bào)表,則用Spark;如果想要做一些流式數(shù)據(jù)的查詢和分析,則可以用Flink之類的工具。
這個(gè)架構(gòu)存在幾個(gè)問(wèn)題:
- 一致性:數(shù)據(jù)分成了三路,彼此之間天然割裂,在這種割裂的情況下,一致性是一個(gè)大問(wèn)題。如果大家在公司里做一些數(shù)據(jù)處理的架構(gòu)如Lambda架構(gòu)等,流和批數(shù)據(jù)的對(duì)齊是一個(gè)繞不開(kāi)的問(wèn)題,因?yàn)閿?shù)據(jù)是多份的,本質(zhì)上仍是一致性問(wèn)題。
- 受限的進(jìn)階分析:如果我們?cè)诤献鰯?shù)據(jù)分析,我們?nèi)狈σ恍└唠A的分析能力,比如更新、快照、ACID等語(yǔ)義存在缺失。
- 數(shù)據(jù)成本:每一個(gè)通路的底層存儲(chǔ)不同,計(jì)算也不一樣,因?yàn)橛?jì)算需要對(duì)應(yīng)的存儲(chǔ)來(lái)決定計(jì)算的性能,所以我們需要拷貝多份數(shù)據(jù),成本也隨之上升。
2.解決之道——湖倉(cāng)一體
大概于20年左右提出了湖倉(cāng)一體的架構(gòu),試圖用一個(gè)統(tǒng)一的湖上建倉(cāng)或湖倉(cāng)一體的存儲(chǔ)架構(gòu),解決數(shù)倉(cāng)和數(shù)據(jù)庫(kù)的問(wèn)題。
針對(duì)傳統(tǒng)意義的數(shù)據(jù)湖,若在對(duì)象存儲(chǔ)或者Hadoop上能夠構(gòu)建出具備數(shù)倉(cāng)語(yǔ)義的一個(gè)格式,使得我們?cè)诤系母袷接懈鼜?qiáng)的能力去做數(shù)倉(cāng),則需要具備幾個(gè)條件:
- 湖上可靠的數(shù)據(jù)管理:即需要一種開(kāi)放的高性能的數(shù)據(jù)組織方式。采用傳統(tǒng)方式定義表時(shí),缺乏一種高效的表的組織方式。我們通常用 Hive表,它就是一個(gè)目錄,沒(méi)有特殊的能力。我們需要一種更高效的組織能力,兼顧一些倉(cāng)的特性。
- 支持機(jī)器學(xué)習(xí)和數(shù)據(jù)科學(xué):湖倉(cāng)一體的技術(shù)需要有一套開(kāi)放的標(biāo)準(zhǔn)或者開(kāi)放的接口。大家在用數(shù)倉(cāng)的時(shí)候,會(huì)發(fā)現(xiàn)它是存算一體的數(shù)倉(cāng),存儲(chǔ)就是為了計(jì)算所定制。雖然性能很好,但不開(kāi)放,也就是所有的生態(tài)都要建立在上面,但數(shù)據(jù)湖則是天然開(kāi)放,F(xiàn)link和Spark等其他引擎都能使用這些數(shù)據(jù)。
- 最先進(jìn)的SQL性能:若湖倉(cāng)一體只是湖,那么很輕易就能辦到,但是它的性能會(huì)比較差。如果要使表具備倉(cāng)的性能,比如能夠匹敵類似Snowflake或者Redshift這樣的性能,則需要一個(gè)高性能的SQL引擎,這也是Databricks做了Photon引擎的原因,有了這些,我們就可以真正在湖上構(gòu)建出一個(gè)高性能的數(shù)倉(cāng),也就是“湖倉(cāng)一體”。
3.三種主流開(kāi)源技術(shù)
前文講述了湖倉(cāng)一體技術(shù)所要具備的幾個(gè)特性,如今在開(kāi)源領(lǐng)域主要有三種技術(shù)擁有這些特性,分別是:Hudi、Iceberg和Delta Lake。
它們的功能整體上比較接近,都是一種數(shù)據(jù)的組織方式,即定義了一種表的格式,這個(gè)格式主要是定義數(shù)據(jù)的組織方式,而不是確定一種數(shù)據(jù)的存儲(chǔ)格式。與一些純粹的數(shù)據(jù)格式或Hive表(Hive 3.0版本前)相比,它提供了ACID事務(wù)能力,這樣就具備了倉(cāng)的能力,它可以提供一些事務(wù)的特性和并發(fā)能力,還可以做行級(jí)數(shù)據(jù)的修改、表結(jié)構(gòu)的修改和進(jìn)化,這些都是傳統(tǒng)大數(shù)據(jù)格式難以完成的事項(xiàng)。湖倉(cāng)一體技術(shù)出現(xiàn)后被業(yè)界迅速采用,從21年開(kāi)始就進(jìn)入了Gartner技術(shù)成熟度曲線的評(píng)估。
4.湖倉(cāng)一體技術(shù)的優(yōu)勢(shì)
- 優(yōu)化數(shù)據(jù)入湖流程:相比傳統(tǒng)的成熟形態(tài),比如T+1的入倉(cāng)形態(tài)或者入湖的形態(tài),它可以用T+0的高效的流式入湖形態(tài),大大降低了數(shù)據(jù)的可見(jiàn)時(shí)延。
- 支持更多的分析引擎:它是開(kāi)放的,所以能夠支持很多引擎。我們內(nèi)部也對(duì)接了很多不同的引擎,包括Flink、Spark 、Presto和StarRocks等。
- 統(tǒng)一數(shù)據(jù)存儲(chǔ)和靈活的文件組織:采用比較靈活的文件組織方式,具備了一些額外的特性,使得流和批都可以用這種文件組織方式進(jìn)行消費(fèi)。
- 增量讀取處理能力
5.湖倉(cāng)一體落地場(chǎng)景
1)加速數(shù)據(jù)入湖
下圖左側(cè)是我們一個(gè)舊的數(shù)據(jù)管道。舉個(gè)例子,要收集一些Spark的審計(jì)日志以觀察每天的情況,那么我們就可以把Spark日志都導(dǎo)入到消息隊(duì)列中。在騰訊內(nèi)部使用的是TubeMQ,然后我們有一個(gè)服務(wù)TDSort用于歸檔,把數(shù)據(jù)按照小時(shí)或者天的時(shí)間格式分類,緊接著保存至HDFS上,再啟動(dòng)一個(gè)Hive的命令,把它添加到分區(qū)內(nèi)。
前面是通過(guò)流式進(jìn)入,后面是批的落盤,整體設(shè)計(jì)比較復(fù)雜。為了保證exactly-once以及保證流轉(zhuǎn)批的可見(jiàn)性,我們?cè)谠有陨匣撕芏嘈乃?,因?yàn)樵谠鹊募軜?gòu)上我們?nèi)狈κ聞?wù)的能力,所以我們通常依賴HDFS的原子性來(lái)保證可見(jiàn)性。
之后我們把整體架構(gòu)遷到了以數(shù)據(jù)湖格式為體系的另一套架構(gòu)中,選擇用Flink來(lái)做流式的入湖,把它寫(xiě)到HDFS上,這樣整體鏈路就變得更為簡(jiǎn)單。對(duì)于Flink寫(xiě)下的數(shù)據(jù),我們主要選擇的是Iceberg,在Flink讀取把它寫(xiě)到Iceberg中,下游就能直接可見(jiàn)。
至此,原先T+1的可見(jiàn)性就變成T+0,這個(gè)是最典型、最常見(jiàn)的一種使用方式。這也是我們內(nèi)部像廣告和視頻號(hào)等業(yè)務(wù)的主要使用方式,把小時(shí)級(jí)的數(shù)據(jù)可見(jiàn)性降低到分鐘級(jí)的可見(jiàn)性。
2)構(gòu)建CDC Pipeline
CDC在騰訊內(nèi)部不算是非常大的場(chǎng)景,但原本通過(guò)拉鏈表方式去構(gòu)建,會(huì)帶來(lái)一些問(wèn)題:一是延遲,二是后續(xù)的處理流程非常復(fù)雜。
我們現(xiàn)在改成了另一種方式,使用Flink的CDC Connector,再加上Hudi。因?yàn)獒槍?duì)CDC而言,Hudi在這方面的能力比Iceberg更成熟,所以選用Hudi而不是Iceberg。
有兩種方案,一種方案是直連MySQL或PostgreSQL等類似的數(shù)據(jù)庫(kù),另一種是通過(guò)消息隊(duì)列的方式,通常都是使用第一種方式,這也是比較常見(jiàn)的一種內(nèi)部形態(tài),與前面相比Flink CDC connector與MySQL直連獲取binlog。
3)近實(shí)時(shí)的流批一體架構(gòu)
在業(yè)務(wù)側(cè)使用整套湖倉(cāng)一體技術(shù)后,從原先的Lambda架構(gòu)轉(zhuǎn)換成了湖倉(cāng)一體的架構(gòu)。在原先的架構(gòu)中,流和批分離,流主要是用消息隊(duì)列來(lái)做流式的Pipeline的構(gòu)建,還有一條離線鏈路做數(shù)據(jù)的回補(bǔ)和對(duì)賬等。但是離線存在于HDFS上,這樣就會(huì)導(dǎo)致兩條鏈路要做同一份數(shù)據(jù)的處理。
使用湖倉(cāng)一體就相當(dāng)于把它們合并,我們?cè)贠DS、DWD或者DWS層統(tǒng)一用Iceberg來(lái)進(jìn)行流式寫(xiě)入。在流式寫(xiě)入后,可以在每一層中做離線或者批的分析,也可以一直做流式分析,因此同一份數(shù)據(jù)既做到了流式的讀和寫(xiě),又做到了批的讀和寫(xiě),一份數(shù)據(jù)就可以適配整個(gè)場(chǎng)景,不需要存多份數(shù)據(jù)或者接多條ETL Pipeline。這就是我們比較典型的一個(gè)架構(gòu),騰訊視頻也是在這個(gè)架構(gòu)基礎(chǔ)上做演進(jìn)。
4)更好的Hive表
回到湖倉(cāng)一體的本質(zhì),即使我們不需要上述的特性,相比傳統(tǒng)的Hive表,它也帶來(lái)了很多新的特性和能力。用于取代離線的場(chǎng)景化,也會(huì)有更好的效果。
數(shù)據(jù)治理:
- 支持表結(jié)構(gòu)進(jìn)化:Hive的其中一個(gè)特性就是分區(qū),在建表的時(shí)候就需要指定分區(qū)字段,同時(shí)在查詢時(shí)也必須加上分區(qū)的過(guò)濾條件,否則它有可能去查所有的分區(qū),造成大量數(shù)據(jù)的誤讀取。分區(qū)一旦定下來(lái)就很難變動(dòng),但I(xiàn)ceberg是隱式的分區(qū),通過(guò)它的表達(dá)式來(lái)做分區(qū)的映射和轉(zhuǎn)換,就可以對(duì)分區(qū)做出調(diào)整,比如原先是按月來(lái)分區(qū),你可以把它更改成按天分區(qū)。
- 支持行級(jí)數(shù)據(jù)的修正:原先Hive表的一個(gè)常見(jiàn)思路是用覆蓋寫(xiě)的方式,要做數(shù)據(jù)修正時(shí)就要覆蓋一個(gè)分區(qū),但你可能只有一行數(shù)據(jù)需要調(diào)整。湖倉(cāng)一體的格式提供了行級(jí)的修正能力。提供兩種修正,一種是Copy On Write的修正,還有一種是Merge On Read的修正,降低了修正的代價(jià),大大提高了它的實(shí)時(shí)性。
數(shù)據(jù)查詢:
- ACID能力:Hive依靠HDFS的原子性來(lái)保證它的可見(jiàn)性。比如你Insert到多個(gè)分區(qū)時(shí),Insert涉及到跨多目錄復(fù)制,則無(wú)法原子性,這時(shí)你一邊 Insert一邊去查詢的時(shí)候就會(huì)讀到臟數(shù)據(jù),Iceberg、Hudi都是通過(guò)快照機(jī)制進(jìn)行查詢,快照只有被commit了以后才可見(jiàn),所以這時(shí)并發(fā)地讀和寫(xiě)數(shù)據(jù),不會(huì)出現(xiàn)任何問(wèn)題。
- 高效的data skipping能力:像這種新的表格式,它會(huì)增加一些額外的能力,比如z-ordering的data skipping的能力,使得你能更高效地做多維數(shù)據(jù)分析。即使沒(méi)有實(shí)時(shí)的需求,只想替換Hive表,那么用湖倉(cāng)一體這些新的表格式也能給你帶來(lái)更好的效果。
二、湖倉(cāng)一體技術(shù)現(xiàn)存的問(wèn)題
1.湖倉(cāng)一體內(nèi)核的性能
隨著湖倉(cāng)一體實(shí)踐的逐漸深入,尤其是當(dāng)單鏈路的數(shù)據(jù)量達(dá)到分鐘級(jí),每日達(dá)到萬(wàn)億規(guī)模時(shí),湖倉(cāng)一體的性能問(wèn)題就要格外重視。
1)數(shù)據(jù)治理問(wèn)題
- 海量小文件:我們主要用Iceberg,它每次commit時(shí)都會(huì)生成大量文件,你要求的commit時(shí)間越短,它的小文件就會(huì)越多,幾天過(guò)去,這張表的小文件數(shù)可能達(dá)到幾百萬(wàn),甚至上千萬(wàn),這個(gè)時(shí)候再去查詢,Query Plan就會(huì)跑不動(dòng),變得非常慢。
- Query Plan時(shí)延:Iceberg保存了多副本,每一次commit都會(huì)產(chǎn)生一個(gè)元數(shù)據(jù)的快照,快照里面包含了很多信息,元數(shù)據(jù)的數(shù)量將越來(lái)越大。如果未做一些元數(shù)據(jù)的清理或者合并,那么只是生成執(zhí)行計(jì)劃就需要大量耗時(shí)。我們內(nèi)部的廣告系統(tǒng)在使用,它是一個(gè)復(fù)雜類型,大概有幾千列的表結(jié)構(gòu)的查詢和嵌套類型的復(fù)雜字段。Iceberg未優(yōu)化的時(shí)候,Query Plan甚至要十幾分鐘。
2)查詢性能問(wèn)題
- 平衡讀寫(xiě)性能:寫(xiě)和讀的對(duì)于性能的要求不同,如何能夠平衡寫(xiě)和讀是非常重要的一個(gè)問(wèn)題。
- 發(fā)揮極速性能:Iceberg和Hudi很多高階的特性,比如索引之類,我們內(nèi)部也進(jìn)行了大量建設(shè)。
3)流批一體
批處理希望能夠有更多的數(shù)據(jù)塊聚合在一起讀取,做到更多樣、更大的吞吐,流則需要更快的響應(yīng)。
2.湖倉(cāng)一體技術(shù)的實(shí)時(shí)性限制
拋開(kāi)內(nèi)核,無(wú)論是Iceberg還是Hudi,本質(zhì)上都是海量文件的組織方式,無(wú)法擺脫存儲(chǔ)的限制,我們通常會(huì)把它存到內(nèi)部的HDFS上,云上則會(huì)存到對(duì)象存儲(chǔ)中。但對(duì)象存儲(chǔ)也有它的限制,吞吐量較大,但延遲會(huì)較高。
如果需要流讀,我們通常在構(gòu)建實(shí)時(shí)鏈路的時(shí)候,會(huì)選擇消息隊(duì)列,它的存儲(chǔ)模型完全不同,是低延遲高響應(yīng),順序讀寫(xiě)。它的存儲(chǔ)能力決定了計(jì)算,流式計(jì)算的訪問(wèn)方式和離線計(jì)算的訪問(wèn)方式不同。
這個(gè)時(shí)候就會(huì)出現(xiàn)兩個(gè)問(wèn)題:
- 如何平衡流式的訪問(wèn)和批的訪問(wèn)?既能做到高性能和高效,又能做到低成本?
- 傳統(tǒng)的Iceberg和Hudi,實(shí)現(xiàn)分鐘級(jí)已經(jīng)接近極限,如果繼續(xù)加速該如何優(yōu)化?
三、騰訊在湖倉(cāng)一體上的工作
1.內(nèi)核優(yōu)化
1)功能優(yōu)化
- 大寬表支持:主要針對(duì)廣告,因?yàn)閺V告需要不斷加入新的特征,隨著添加的特征越來(lái)越多,表就會(huì)變得越來(lái)越寬。同時(shí),它原來(lái)使用PB的格式,所以它有很多嵌套,現(xiàn)在把它轉(zhuǎn)成Iceberg,就變成了一個(gè)極大的寬表,無(wú)論對(duì)于寫(xiě)入還是查詢,都極具挑戰(zhàn)。
- 跨源查詢支持:因?yàn)閮?nèi)部有舊表、新表以及不同的系統(tǒng),所以需要實(shí)現(xiàn)跨源以及高性能的查詢。
- 流轉(zhuǎn)批:我們絕大多數(shù)的鏈路仍是批,為使在流式寫(xiě)入時(shí)下游能夠具有批的可見(jiàn)性,我們?cè)黾恿薟atermark機(jī)制來(lái)進(jìn)行流轉(zhuǎn)批。
- 流式寫(xiě)入支持去重、增量讀取、流量控制:我們不斷改進(jìn)流式寫(xiě)入能力,尤其是對(duì)于在Iceberg上做CDC的寫(xiě)入,部分列的更新等,做了很多改進(jìn)。
2)性能優(yōu)化
- 元數(shù)據(jù)讀取加速, 引入Alluxio:引入Alluxio,把元數(shù)據(jù)緩存在Alluxio上,加速它的訪問(wèn),對(duì)并行的元數(shù)據(jù)的Query Plan、壓縮格式等也做了一些調(diào)整,實(shí)現(xiàn)加速;
- 復(fù)雜類型列剪支優(yōu)化, 基于列信息任務(wù)切分優(yōu)化;
- V2表layout改進(jìn)與合并加速;
- 向量化,Async-IO,CBO等查詢加速。
總體來(lái)看,設(shè)計(jì)出這些特性后,測(cè)試數(shù)據(jù)顯示,我們內(nèi)部的TDW與Spark相比,性能大大提升。
2.二級(jí)索引
Snowflake或者Redshift之所以那么快,很重要的一點(diǎn)是因?yàn)樗兴饕覀儌鹘y(tǒng)的Hive表幾乎沒(méi)有索引。Iceberg具備了構(gòu)建索引的能力,也具有ACID能力,而且它的表結(jié)構(gòu)也更復(fù)雜,所以我們能夠構(gòu)建索引。
具體成果:1)引入一個(gè)索引框架;2)構(gòu)建了不同類型的索引。
我們做的是全局索引,針對(duì)每個(gè)Data File生成對(duì)應(yīng)的Index File。Index file與datafile綁定,內(nèi)部有一套系統(tǒng)會(huì)異步更新或者生成Index。我們選擇Puffin作為存儲(chǔ)的格式,它是Iceberg定義的一種Index的存儲(chǔ)格式。我們也改造了一定的語(yǔ)法,使得它能夠支持索引的生成。
整體完成后,我們有一個(gè)點(diǎn)查的場(chǎng)景,bloom filter就比較適合點(diǎn)查的場(chǎng)景,速度與原來(lái)相比有一個(gè)數(shù)量級(jí)的提升。
3.流批一體的實(shí)時(shí)湖倉(cāng)架構(gòu)
我們?cè)谑褂煤}(cāng)一體技術(shù)的時(shí)候,流式的性能已無(wú)法實(shí)現(xiàn)突破,因?yàn)槭苤朴诘讓拥拇鎯?chǔ),使用HDFS或者對(duì)賬存儲(chǔ)則缺乏更低的延時(shí),所以我們也在參考社區(qū)的方案。
Flink社區(qū)提供了一個(gè)Flink Table Store的方案,把流存儲(chǔ)和批存儲(chǔ)融合為一體,現(xiàn)在改了名字,叫做Paimon,我們參考其做了類似的方案。在這個(gè)方案中,流和批選擇了不同的存儲(chǔ),流選擇使用消息隊(duì)列,批則是底層使用數(shù)據(jù)湖的格式,封裝在一起就成為了流批表。有了流批表,則能夠?qū)ν馓峁┙y(tǒng)一的流和批的讀寫(xiě)接口。
我們主要是對(duì)接Flink的場(chǎng)景,寫(xiě)的時(shí)候我們會(huì)雙寫(xiě)到LogStore和Filestore這兩個(gè)系統(tǒng)中,根據(jù)不同的場(chǎng)景讀不同的系統(tǒng)。如果是流式則讀LogStore,批則讀Filestore。
優(yōu)點(diǎn):
- 引擎和表的流批一體,降低業(yè)務(wù)架構(gòu)復(fù)雜度:存儲(chǔ)在形態(tài)上可以看成近似的統(tǒng)一體,未來(lái)也希望能實(shí)現(xiàn)真正的統(tǒng)一。
- 屏蔽流批差異,統(tǒng)一SQL操作:我們把Flink和流批對(duì)接后,就可以在Flink上提供流和批的處理能力,只需要使用同一套引擎。
- 提升時(shí)效性,兼顧流式和湖倉(cāng):因?yàn)榱鲗?xiě)到了消息隊(duì)列中,所以流的性能提高,速度加快,能實(shí)現(xiàn)秒級(jí)的時(shí)效性。
4.自動(dòng)數(shù)據(jù)治理
我們引入了自動(dòng)數(shù)據(jù)治理的概念,它與傳統(tǒng)的數(shù)據(jù)治理方式的區(qū)別在于它基于事件驅(qū)動(dòng),而不是基于時(shí)間定時(shí)完成。其具備以下能力:
- 做文件的聚合,包括排序聚合和zordering聚合;
- 可以做行級(jí)或者列級(jí)的生命周期的管理;
- 自動(dòng)的索引、緩存和排序等。
具體的運(yùn)作步驟:它會(huì)在Iceberg的存儲(chǔ)中收集一些事件,根據(jù)事件分析當(dāng)前要進(jìn)行的操作,然后根據(jù)規(guī)則來(lái)生成這些操作。
1)小文件合并
在做小文件合并時(shí),如何生成這些規(guī)則?
傳統(tǒng)意義上的小文件合并,通常來(lái)會(huì)設(shè)定一個(gè)時(shí)間點(diǎn),比如每隔一小時(shí)或者每隔一天做一次,但這樣會(huì)產(chǎn)生很多無(wú)效的作業(yè)。若你的寫(xiě)入很快,那么可能會(huì)有大量的堆積,若你寫(xiě)入很慢,那么就可能有很多無(wú)效的合并操作。
我們通過(guò)收集每一次commit后寫(xiě)入的增量,求均方差,判斷當(dāng)前是否達(dá)到閾值。若未到閾值,我們會(huì)逐步更新它的均方差。如果達(dá)到閾值,就會(huì)觸發(fā)一個(gè)小文件的合并操作,根據(jù)事件來(lái)驅(qū)動(dòng)。這樣的形式會(huì)比先前的方式更能節(jié)省資源,效率也更高。
2)自動(dòng)重分布優(yōu)化
現(xiàn)在社區(qū)也有,但我們更早開(kāi)始,它主要是能夠做到加速多維查詢,把相關(guān)的record歸類放在一起。我們會(huì)通過(guò)事件收集相關(guān)性極高常被查詢的列,自動(dòng)給用戶推薦可以重排列的數(shù)據(jù),并詢問(wèn)是否需要重排列。當(dāng)用戶決定重排列,數(shù)據(jù)就會(huì)進(jìn)行增量,做后續(xù)的重排列,這樣就能提高數(shù)據(jù)整體的有效過(guò)濾率。
3)自動(dòng)索引
我們對(duì)Iceberg引入了一個(gè)索引框架,支持bloom filter 和 bitmap的構(gòu)建,但是用戶并不知道如何使用索引。所以我們提供了自動(dòng)索引的構(gòu)建能力,會(huì)根據(jù)查詢的信息分析出哪些列的用戶查詢頻度較高,接下來(lái)我們會(huì)優(yōu)先在這些列上構(gòu)建索引。同時(shí),我們選擇了根據(jù)分區(qū)的增量來(lái)加theta sketch的方式來(lái)做增量的索引,而不是每次都做全表索引的重構(gòu)。構(gòu)建索引后,Iceberg的常用性能會(huì)出現(xiàn)一個(gè)大的躍升。
四、后續(xù)規(guī)劃
我們希望湖倉(cāng)建設(shè)從原先的準(zhǔn)實(shí)時(shí)湖倉(cāng)向?qū)崟r(shí)湖倉(cāng)的架構(gòu)邁進(jìn),也希望湖倉(cāng)一體架構(gòu)在經(jīng)過(guò)元數(shù)據(jù)、緩存和索引的優(yōu)化后,能夠解決交互式查詢和流的所有場(chǎng)景問(wèn)題,用一套存儲(chǔ)應(yīng)對(duì)所有的場(chǎng)景。這是我們現(xiàn)在在做的事情,也是未來(lái)的目標(biāo)。
Q&A
Q1:前面提及CDC的構(gòu)建,是按照整庫(kù)入倉(cāng)還是按表的方式來(lái)進(jìn)行?
A1:我們騰訊這邊的量不算大,我們內(nèi)部主要還是以append方式入湖,CDC則仍是按表的方式來(lái),沒(méi)有做太多的優(yōu)化,也沒(méi)有涉及整庫(kù)的方式。
Q2:您提到小文件合并,具體的優(yōu)化是指要另起一個(gè)旁路作業(yè),還是指將這部分的功能并入到寫(xiě)入的流程里?
A2:我們采取離線和異步的方式,因?yàn)槿绻⑷氲綄?xiě)入的流程,會(huì)對(duì)整體寫(xiě)入造成拖垮或者堆積效應(yīng),所以根據(jù)我們內(nèi)部的實(shí)踐以及單鏈路1000多億的日均寫(xiě)入的經(jīng)驗(yàn),同步寫(xiě)入和合并的這種方案并不可行,所以我們做的是異步方案。
Q3:有些場(chǎng)景會(huì)選擇Hudi,另外一些場(chǎng)景選擇Iceberg,請(qǐng)問(wèn)Iceberg和Hudi的選型依據(jù)是什么?
A3:我們八成以上的場(chǎng)景都選擇了Iceberg,因?yàn)槲覀兺渡砑笆褂肐ceberg社區(qū)的時(shí)間較早,所以對(duì)Iceberg的的整體把控會(huì)更好。只有涉及CDC的場(chǎng)景,我們才會(huì)用Hudi,因?yàn)镮ceberg當(dāng)前的CDC能力不夠成熟,但我們也在探索和建設(shè)Iceberg的CDC能力,包括全局索引的能力、部分列的更新能力等,也是為了全鏈路CDC所做的優(yōu)化。如果未來(lái)Iceberg具備這樣的能力,我們應(yīng)該會(huì)統(tǒng)一使用Iceberg,因?yàn)榫S護(hù)多套系統(tǒng)會(huì)增加維護(hù)的成本。其實(shí)這兩個(gè)技術(shù)沒(méi)有太大差別,只需選擇一種即可,實(shí)際上社區(qū)的演進(jìn)最終都會(huì)趨同。
Q4:Iceberg上有Spark和Flink等多個(gè)引擎,假如我建了一個(gè)Iceberg表,可以用Spark和Flink兩種引擎同時(shí)訪問(wèn)底層的表嗎?
A4:可以。因?yàn)樗兴^的事務(wù)的語(yǔ)義。這也取決于你的鎖如何實(shí)現(xiàn),默認(rèn)使用比如HiveLock等可以做隔離,所以能夠多引擎地去寫(xiě),但會(huì)有一定的沖突概率。但針對(duì)讀而言,因?yàn)镮ceberg生成的每一個(gè)副本都是只讀的,所以多引擎去讀沒(méi)有任何問(wèn)題。
Q5:數(shù)據(jù)湖在應(yīng)用側(cè)的使用場(chǎng)景有哪些?
A5:數(shù)據(jù)湖從20年初引入到現(xiàn)在,在騰訊內(nèi)部每年至少有10倍以上的規(guī)模增長(zhǎng),所以現(xiàn)在幾乎所有的業(yè)務(wù)線都在使用。最大的業(yè)務(wù)線一般是視頻號(hào)或者廣告之類,也有其他的業(yè)務(wù),基本上所有的業(yè)務(wù)都在用數(shù)據(jù)湖,無(wú)論是用于加速數(shù)據(jù)的可見(jiàn)性、構(gòu)建CDC還是用Iceberg替代Hive表的低效查詢,都會(huì)帶來(lái)一定的性能提升,這些場(chǎng)景前文有所提及。
作者介紹
邵賽賽,前騰訊實(shí)時(shí)湖倉(cāng)團(tuán)隊(duì)負(fù)責(zé)人,現(xiàn)Co-Founder & CTO of Datastrato。Apache基金會(huì)成員,Apache Spark Inlong Livy PMC成員,曾就職于Hortonworks、Intel,10年的大數(shù)據(jù)從業(yè)經(jīng)驗(yàn),專注于分布式流批計(jì)算引擎的研發(fā)和優(yōu)化。