愛(ài)奇藝數(shù)據(jù)湖平臺(tái)建設(shè)實(shí)踐
一、愛(ài)奇藝 OLAP 簡(jiǎn)介
首先簡(jiǎn)單介紹一下愛(ài)奇藝 OLAP 的基本情況:
存儲(chǔ)方面,OLAP 目前支持三類存儲(chǔ):
① 離線 HDFS:用于離線分析、批處理等場(chǎng)景;
② 實(shí)時(shí) Kafka:用于實(shí)時(shí)分析、在線處理等場(chǎng)景;
③ 近實(shí)時(shí) Iceberg:分鐘級(jí)延遲,是今天要重點(diǎn)介紹的數(shù)據(jù)湖產(chǎn)品。
存儲(chǔ)之上是查詢引擎,我們采用 SparkSQL 做 ETL 處理,采用 Trino 做 Ad-hoc 即席查詢,ClickHouse 用于查詢加速的場(chǎng)景。我們通過(guò) Pilot 提供對(duì)外的統(tǒng)一查詢,支持各類應(yīng)用場(chǎng)景。
二、為什么要數(shù)據(jù)湖
下面來(lái)介紹一下愛(ài)奇藝數(shù)據(jù)湖的建設(shè)背景。
1、數(shù)據(jù)湖技術(shù)加速數(shù)據(jù)流通
為什么要有數(shù)據(jù)湖?數(shù)據(jù)湖其實(shí)就是為了加速數(shù)據(jù)流通。
愛(ài)奇藝 Pingback 投遞的場(chǎng)景:
Pingback 是愛(ài)奇藝內(nèi)部對(duì)端上埋點(diǎn)的習(xí)慣名稱,每個(gè)公司都會(huì)有類似的服務(wù)。在經(jīng)典的 Lambda 架構(gòu)解決方案里,Pingback 數(shù)據(jù)在投遞后,有離線和實(shí)時(shí)兩個(gè)通路。
離線通路寫到 HDFS 里,然后由離線開發(fā)平臺(tái)構(gòu)建離線數(shù)倉(cāng)。離線數(shù)倉(cāng)的優(yōu)點(diǎn)是成本很低,支持的容量也很大。缺點(diǎn)是延遲大,可能要 1 小時(shí)或者 1 天。為了解決這個(gè)時(shí)效性問(wèn)題,往往會(huì)再構(gòu)建一個(gè)實(shí)時(shí)數(shù)倉(cāng)。通常用 Kafka 作為存儲(chǔ),用 Flink 或者 Spark 這類的流計(jì)算任務(wù)處理 Kafka 數(shù)據(jù),構(gòu)建實(shí)時(shí)數(shù)倉(cāng)。
實(shí)時(shí)數(shù)倉(cāng)的延遲非常低,能做到秒級(jí)的延遲,但缺點(diǎn)是成本很高,只能放最近幾個(gè)小時(shí)的數(shù)據(jù),要基于 Kafka 做明細(xì)查詢也是比較的困難的。
其實(shí)很多實(shí)時(shí)分析場(chǎng)景并不需要秒級(jí)的延遲,分鐘級(jí)的延遲就足夠了。譬如說(shuō)廣告、會(huì)員的運(yùn)營(yíng)場(chǎng)景,或者監(jiān)控大盤等。數(shù)據(jù)湖產(chǎn)品提供了性價(jià)比很高,容量很大的分鐘級(jí)延遲的解決方案。
2、Iceberg 定義-新型表格式
愛(ài)奇藝的數(shù)據(jù)湖選型用的是 Iceberg,Iceberg 是一種新設(shè)計(jì)的開源表格式,用于大規(guī)模數(shù)據(jù)分析。
① Iceberg 本質(zhì)上不是存儲(chǔ),因?yàn)樗讓哟鎯?chǔ)復(fù)用了 HDFS,或者對(duì)象存儲(chǔ)。在存儲(chǔ)之上構(gòu)建了 Iceberg 表級(jí)抽象,對(duì)標(biāo) Hive 的表設(shè)計(jì)。
② 它也不是查詢引擎或者流計(jì)算引擎,它支持各類計(jì)算引擎,比如 Hive、 Flink、 Spark,也支持各類的 SQL 查詢引擎。
(1)表格式-Hive 及其缺陷
為什么有了 Hive 表格式還要引入 Iceberg 表格式?
一個(gè)經(jīng)典的 Hive 表可能會(huì)有天級(jí)分區(qū)、小時(shí)級(jí)分區(qū),或者進(jìn)一步的子分區(qū)。其設(shè)計(jì)核心是用目錄樹去組織數(shù)據(jù),能夠很好地做分區(qū)級(jí)過(guò)濾。
但是它也有著以下缺點(diǎn):
① 元數(shù)據(jù)統(tǒng)一存在 Metastore,通常底下是 MySQL,很容易成為瓶頸。
② 由于元信息是分區(qū)級(jí)別的,沒(méi)有文件級(jí)別的信息,因而當(dāng)發(fā)起一個(gè)查詢時(shí),制定執(zhí)行計(jì)劃需要拿到分區(qū)下的文件列表。拿到文件列表本質(zhì)上是對(duì)每一個(gè)分區(qū)請(qǐng)求 NameNode 做 List 請(qǐng)求。舉個(gè)例子,一天有 200 多個(gè)分區(qū),查 7 天的數(shù)據(jù),分區(qū)數(shù)就會(huì)非常多,會(huì)發(fā)起 O(N) 復(fù)雜度的 NameNode 的 List 請(qǐng)求調(diào)用,這個(gè)元數(shù)據(jù)的枚舉過(guò)程會(huì)非常的慢。
③ 由于它的最小單位是分區(qū)級(jí)別的,最大的原子操作就是分區(qū)級(jí)別的覆蓋,其他一些原子操作是不支持的。
(2)表格式-Iceberg
Iceberg 新定義的表結(jié)構(gòu)有元數(shù)據(jù)層和數(shù)據(jù)層。數(shù)據(jù)層就是數(shù)據(jù)文件。元數(shù)據(jù)層是它很重要的設(shè)計(jì)點(diǎn),可以復(fù)用 Hive 的 MetaStore,指向最新的快照。元數(shù)據(jù)里面分多層,記錄了具體的文件列表。
每次有新的 Commit,就會(huì)創(chuàng)建出新的快照,讀請(qǐng)求可以訪問(wèn)舊的快照,寫請(qǐng)求寫新的。在寫的過(guò)程中,新創(chuàng)建的數(shù)據(jù)文件讀是不可見(jiàn)的,只有在提交后把最新的版本指過(guò)去,新寫入的文件才可見(jiàn)。做到了讀寫分離。同時(shí)修改操作是原子的,能夠支持細(xì)粒度的分區(qū)內(nèi)部的修改。
(3)表格式-Hive VS Iceberg
簡(jiǎn)單比較一下 Hive 和 Iceberg:兩者底層都采用 HDFS 或者對(duì)象存儲(chǔ),都是 PB 級(jí)的廉價(jià)存儲(chǔ)方案。區(qū)別 Hive 元信息是分區(qū)級(jí),Iceberg 是文件級(jí)。比如 Hive 分區(qū)原本有 100 個(gè)文件,加了 5 個(gè)文件,那么 Hive 下游任務(wù)就需要重新計(jì)算 Hive 分區(qū)下的全部數(shù)據(jù)。Iceberg 能夠獲取到修改的 5 個(gè)文件,可以做增量的下游計(jì)算。
時(shí)效性是 Iceberg 很明顯的優(yōu)勢(shì),能夠做到近實(shí)時(shí),比如 5 分鐘級(jí),如果每分鐘提交一次則可以做到分鐘級(jí)。
制定執(zhí)行計(jì)劃時(shí),Iceberg 是常數(shù)級(jí)的,它只讀取固定的元數(shù)據(jù)文件就能夠拿到文件列表。
Iceberg 還支持文件級(jí)別的過(guò)濾,比如基于統(tǒng)計(jì)信息或者字典做過(guò)濾。
三、數(shù)據(jù)湖平臺(tái)建設(shè)
為了方便用戶使用,愛(ài)奇藝在引入數(shù)據(jù)湖以后,首先要做平臺(tái)化建設(shè)。
1、平臺(tái)總覽
這是愛(ài)奇藝數(shù)據(jù)湖整體的產(chǎn)品架構(gòu)圖:
最底下是數(shù)據(jù)源,比如前面提到的 Pingback、用戶 MySQL 的 Binlog 解析、日志和監(jiān)控信息,會(huì)分別進(jìn)到實(shí)時(shí)、離線和 Iceberg 通道。在 Iceberg 之上,通過(guò) RCP 平臺(tái)、Babel 平臺(tái)分別做流式入湖和離線入湖。使用 Trino 和 Spark SQL 去做查詢。同時(shí)我們開發(fā)了數(shù)據(jù)湖平臺(tái)去完成元數(shù)據(jù)管理、權(quán)限管理等等。
2、流式入湖
愛(ài)奇藝通過(guò)實(shí)時(shí)計(jì)算平臺(tái),能夠做到很簡(jiǎn)單的入湖。一個(gè) Kafka 的數(shù)據(jù)只需要三步,就可以完成配置流任務(wù):首先配置從哪個(gè) Kafka 開始讀;然后在里面做 Transform 邏輯,比如篩選、重命名,最后定義寫到哪個(gè) Iceberg。
3、出湖查詢
入湖的下一步是查詢,也就是出湖。目前 Iceberg 有兩類文件格式,V1 格式支持 Append Only 數(shù)據(jù),不支持行級(jí)修改。Iceberg 發(fā)布的最新版本 V2 格式能支持行級(jí)更新。
目前 V1 格式是通過(guò) Trino 引擎查詢,V2 格式通過(guò) SparkSQL 查詢。前端是通過(guò) Pilot,我們的自研 SQL 引擎做分發(fā),能夠基于文件格式自動(dòng)地選擇引擎,支持各類用戶場(chǎng)景。
四、性能優(yōu)化
下面介紹一些性能優(yōu)化的工作。
1、小文件
說(shuō)到數(shù)據(jù)湖,無(wú)論哪個(gè)產(chǎn)品都繞不開的一個(gè)問(wèn)題就是小文件問(wèn)題。Hive 可以批量,比如每小時(shí)做一次計(jì)算,可以寫出很大的文件。在 Iceberg 中,由于需要做到近實(shí)時(shí),每分鐘或者每 5 分鐘寫文件,文件就比較小,必然會(huì)有小文件問(wèn)題。我們主要通過(guò)兩個(gè)方面去解決小文件問(wèn)題:
(1)生命周期
根據(jù)表的生命周期做處理。比如一張表可能只需要保留一年,或者保留 30 天,歷史的數(shù)據(jù)可以刪除。
目前平臺(tái)會(huì)限制用戶建表必須配置生命周期,通過(guò)數(shù)據(jù)湖平臺(tái)自動(dòng)地完成清理邏輯。
清理用的是 Iceberg 官方提供的解決方案,Spark 的 Procedure,先是 Drop 分區(qū),然后 Expire 歷史的 Snapshot,再刪除孤兒文件,最后重寫元數(shù)據(jù)文件。
這套流程直接跑,有些環(huán)節(jié)是存在性能問(wèn)題的,并不能夠滿足清理的效率:
① 第一:Spark 的使用模式,每次跑任務(wù)都需要提交一個(gè) Spark 任務(wù),需要先申請(qǐng)Yarn 資源,再啟動(dòng) Application,跑完這個(gè)任務(wù)后這個(gè) Application 就釋放掉了。這里可以采用 Spark 的常駐模式,生命周期清理 SQL 可以跑得很快, 資源是不釋放的,避免了申請(qǐng)和啟動(dòng)的耗時(shí)。
② 第二:天級(jí)的目錄刪除,Iceberg 官方的實(shí)現(xiàn)是比較慢的。它用的是孤兒文件刪除的策略,在文件數(shù)比較多的時(shí)候,掃描過(guò)程比較慢。我們做了改進(jìn),因?yàn)槊鞔_知道整個(gè)天級(jí)目錄都不需要,可以直接刪除整個(gè)目錄。
③ 第三:我們添加了回收站的機(jī)制,生命周期誤刪除時(shí)能有恢復(fù)的手段。
做了這些優(yōu)化以后,線上大概幾千個(gè)表,都能夠按時(shí)完成生命周期的清理。比如 Venus 庫(kù)原先可能有 2 億個(gè) iNode,清理完以后穩(wěn)定在 4000 萬(wàn)的數(shù)量級(jí)。
(2)智能合并
另外一個(gè)處理小文件問(wèn)題的方式就是合并。最簡(jiǎn)單的就是配置一個(gè)定時(shí)合并。
人工配置定時(shí)合并比較大的問(wèn)題是:定時(shí)策略比較難配置。比如,什么時(shí)機(jī)應(yīng)該做合并,這次合并應(yīng)該要合并什么范圍的數(shù)據(jù),如果讓業(yè)務(wù)去配這些信息,每一個(gè) Iceberg 用戶就需要非常深入地去理解小文件產(chǎn)生的機(jī)理才能夠比較好地控制合并的范圍。
為了解決這個(gè)問(wèn)題,我們參考了 Netflix 的文章,做了智能合并,它的核心思想是:
不再由用戶指定合并行為,而是統(tǒng)計(jì) Iceberg 表每個(gè)分區(qū)下面的文件數(shù),計(jì)算均方差,再結(jié)合表的權(quán)重因子,算出來(lái)哪些表合并以后效果是最好的,添加到待合并的分區(qū)列表里面。然后由合并任務(wù)按照優(yōu)先級(jí)完成合并過(guò)程,用戶無(wú)需做配置。
(3)合并性能優(yōu)化
有了智能合并以后,還要解決合并的性能優(yōu)化問(wèn)題,我們也一直跟隨社區(qū)的發(fā)展。在使用過(guò)程中,最初 Iceberg 在文件合并這塊做得還不是很好。最早的時(shí)候,有個(gè)問(wèn)題,Delete File 在合并以后并沒(méi)有被真正地刪除,目前已經(jīng)修復(fù)。舉個(gè)例子,如果 Delete 以后馬上有個(gè) Rewrite Data File,那么相應(yīng)的 Delete File 是不會(huì)被刪除的。這個(gè)問(wèn)題目前有一些解決方案,但最標(biāo)準(zhǔn)的解決方案,社區(qū)還在跟進(jìn)當(dāng)中。
還有一些大表合并任務(wù)經(jīng)常失敗。這里我們可以配置 Bucket 分區(qū),將全表合并改為每次合并其中一個(gè) Bucket 分區(qū),減少單次合并的數(shù)據(jù)量。
還可以應(yīng)用 Binpack 合并策略去控制合并選擇的邏輯。應(yīng)用 Bucket 分區(qū)和 Binpack合并策略以后,如右上示意圖體現(xiàn)的是文件數(shù)的變化,可以判斷這個(gè)文件數(shù)一直在增長(zhǎng),這個(gè)小的下降是小時(shí)級(jí)分區(qū)合并,到一定時(shí)間做全表合并,它的文件數(shù)據(jù)減少得比較多,存在周期性的震蕩。
還有一個(gè)例子,我們發(fā)現(xiàn)在做合并的時(shí)候經(jīng)常會(huì)和寫入任務(wù)沖突,會(huì)報(bào)一個(gè)錯(cuò)誤,要合并的這個(gè)文件有一個(gè) Position Delete 在引用,其實(shí)是一個(gè)誤判,因?yàn)樵谏鐓^(qū)的默認(rèn)的參數(shù)里面,去判斷這個(gè) Data File 有沒(méi)有被新的 Delete File 引用的時(shí)候,有Upper bound 和 Lower bound,但這兩個(gè) Bound 被截取了,這個(gè) Data File 其實(shí)沒(méi)有被引用,但截取以后它就在這個(gè)區(qū)間里面了,解決方法修改表屬性控制相應(yīng)行為。
(4)寫入?yún)?shù)控制
前文介紹了當(dāng)小文件已經(jīng)產(chǎn)生的時(shí)候如何優(yōu)化,但我們更希望小文件最好不要產(chǎn)生,在寫入的時(shí)候就把文件數(shù)控制住。我們需要去了解 Flink 任務(wù)寫入的時(shí)候是怎么控制文件數(shù)量的。
左上角示意圖中這個(gè) Flink 任務(wù)有 100 個(gè)并行度,在默認(rèn)參數(shù) Distribution-mode = None 時(shí)每一個(gè)并行度都會(huì)往分區(qū)下寫文件,就會(huì)寫入 100 個(gè)文件,一分鐘寫 100 個(gè)文件每個(gè)數(shù)據(jù)文件都很小。
如果配置 Distribution-mode = Hash,如左下角的圖中,在寫入的時(shí)候會(huì)先做 Shuffle,基于 Partition Key Shuffle 到特定的 Sink,這個(gè) Flink 任務(wù)會(huì)把數(shù)據(jù)都集中到一個(gè) Sink,寫到一個(gè)文件,就解決了小文件問(wèn)題。
但又會(huì)引入新的問(wèn)題,數(shù)據(jù)量比較大的時(shí)候,單個(gè)任務(wù)寫文件的效率跟不上,就會(huì)造成 Flink 任務(wù)反壓。這個(gè)時(shí)候我們用哈希策略結(jié)合 Bucket 分區(qū)。比如,可以控制 1 個(gè) Hour 下面 10 個(gè) Bucket,通過(guò)兩者結(jié)合起來(lái)就可以很精確地去控制 1 個(gè)分區(qū)到底要生產(chǎn)多少個(gè)文件。一般建議寫入文件大概在 100 MB 左右是比較合適的。上圖的表格中列出了各個(gè)參數(shù)配置下的文件數(shù)量。
2、查詢優(yōu)化
解決了小文件問(wèn)題,接下來(lái)是查詢的性能問(wèn)題。在最初做 Iceberg 性能驗(yàn)證的時(shí)候,我們發(fā)現(xiàn)它的批量 Scan 性能是非常好的,但是點(diǎn)查詢的性能就比較糟糕。
(1)ID 查詢慢
舉個(gè)例子,在訂單表中,用特定 ID,如訂單 ID 或者用戶 ID 去查詢明細(xì),簡(jiǎn)化后的SQL 就是 order_id = ‘555’。默認(rèn)的情況下,Iceberg 會(huì)基于 MinMax 做過(guò)濾,但數(shù)據(jù)按照時(shí)間戳排序,MinMax 過(guò)濾其實(shí)是不生效的,比如 File A 的 MinMax 范圍包含 555,F(xiàn)ile N MinMax 321 到 987 也包含 555,其實(shí)是過(guò)濾不掉的。因而點(diǎn)查詢事實(shí)上就是全表掃描。
針對(duì)點(diǎn)查詢場(chǎng)景,BloomFilter 是非常適用的。最初社區(qū)沒(méi)有這個(gè)功能,Parquet 在 1.12 的時(shí)候支持 BloomFilter,Iceberg 的默認(rèn)存儲(chǔ)格式也是 Parquet,所以我們考慮修改 Iceberg 引入這一功能。
(2)開啟 BloomFilter
先介紹一下 BloomFilter 的作用,在這個(gè)架構(gòu)圖中,比如,針對(duì) order_id 開啟了 BloomFilter,為每一個(gè)數(shù)據(jù)文件構(gòu)建 BloomFilter,將 order_id 進(jìn)行哈希后映射到對(duì)應(yīng) bit,如果值存在就把對(duì)應(yīng)的位設(shè)為 1,如果不存在對(duì)應(yīng)的位默認(rèn)是 0。在 Bloom Filter 里面,如果標(biāo)志位為 1,這個(gè)值不一定存在,但如果標(biāo)志位為 0,這個(gè)值一定不存在。通過(guò)努力,我們?cè)?Iceberg 的內(nèi)核里面添加了相應(yīng)的支持。在 Spark 讀取 Iceberg 和 Trino 讀取的時(shí)候也添加了相應(yīng)的能力。
BloomFilter 支持 Equals 和 In 過(guò)濾。如果標(biāo)志位為 0 是一定能過(guò)濾的。不支持 not equals、not in、比較符等過(guò)濾條件。
示意圖中 order_id = 555 這個(gè)條件,哈希后另外兩個(gè)文件對(duì)應(yīng)的標(biāo)志位值都是 0,在查詢的時(shí)候就可以很快地把其他文件過(guò)濾掉了,能夠精確命中訂單所在的數(shù)據(jù)文件。
(3)BloomFilter 效果
經(jīng)過(guò)測(cè)試,在 Spark SQL 中的訂單 ID 查詢,原來(lái)全表掃描需要將近 1000 秒,開啟 BloomFilter 后只需要 10 秒鐘。Trino 開啟 BF 后,可以過(guò)濾 98.5% 的查詢,CPU 消耗只有以前的 5%。
BloomFilter 會(huì)帶來(lái)額外的空間開銷。經(jīng)過(guò)簡(jiǎn)單的測(cè)試,大概有 3% 的額外空間損耗。即 3% 的存儲(chǔ)代價(jià)可以帶來(lái)點(diǎn)查詢 100 倍的提升。
(4)Alluxio 緩存
查詢優(yōu)化另外一個(gè)工作是緩存加速,如使用 Alluxio 做緩存加速。
這是愛(ài)奇藝 Trino 查數(shù)據(jù)湖的架構(gòu)圖。業(yè)務(wù)通過(guò) Pilot 引擎分發(fā)到 Trino 網(wǎng)關(guān),自動(dòng)地選擇使用哪個(gè) Trino 集群執(zhí)行查詢。原本 Trino Worker 上面的 SSD 存儲(chǔ)是浪費(fèi)的,我們?cè)谥匣觳剂?Alluxio,復(fù)用了原本閑置的 SSD 存儲(chǔ),幾乎沒(méi)有什么額外機(jī)器開銷。
以前去查 HDFS 可能會(huì)有性能抖動(dòng),比如,業(yè)務(wù)有一個(gè)大的批任務(wù),導(dǎo)致 HDFS 性抖動(dòng),查詢性能會(huì)降得很厲害,Alluxio 緩存能夠很好地屏蔽這一點(diǎn)。經(jīng)過(guò)測(cè)試 Venus 日志應(yīng)用 Alluxio 以后,P90 從 18 秒可以降低到 1 秒。
(5)Trino 元數(shù)據(jù)讀取問(wèn)題
在實(shí)際的使用過(guò)程中發(fā)現(xiàn) Trino 查詢有個(gè)意想不到的問(wèn)題,元數(shù)據(jù)讀取性能遠(yuǎn)比我們想象中的要慢。比如,讀取一個(gè) 5 M 的元數(shù)據(jù)竟然要 3 秒鐘,后面查數(shù)據(jù)可能只需要 1 秒,元數(shù)據(jù)反而更慢。
通過(guò)火焰圖和阿里的 Arthas 做定位,發(fā)現(xiàn) Read 的方法被調(diào)用了百萬(wàn)次,文件總共 5 M,讀取 100 多萬(wàn)次是非常不合理的。進(jìn)一步跟蹤,定位原因是父類里面一個(gè) Read 方法的默認(rèn)實(shí)現(xiàn)會(huì)逐個(gè) Byte 讀取,Trino 這邊沒(méi)有覆蓋這個(gè)方法的實(shí)現(xiàn),就會(huì)降級(jí)到默認(rèn)方法,每次讀 1 個(gè) Byte ,所以調(diào)用次數(shù)非常多,導(dǎo)致很慢,優(yōu)化以后耗時(shí)縮短到了 0.5 秒。
五、業(yè)務(wù)落地
最后來(lái)介紹業(yè)務(wù)落地的情況,在應(yīng)用了上述優(yōu)化后,業(yè)務(wù)能取得什么樣的效果。
1、廣告流批一體
第一個(gè)例子是廣告的流批一體場(chǎng)景。原來(lái)的實(shí)時(shí)鏈路中,實(shí)時(shí)數(shù)據(jù)通過(guò) Kafka 寫到 Kudu,離線數(shù)據(jù)同步到 Hive,通過(guò) Impala 來(lái)統(tǒng)一查詢,基于離線覆蓋的進(jìn)度將查詢分發(fā)到 Kudu 和 Hive。
使用 Iceberg 以后,實(shí)時(shí)和離線數(shù)據(jù)都更新 Iceberg,不需要進(jìn)度管理,直接查詢 Iceberg 表即可。Iceberg 實(shí)現(xiàn)了兩方面的統(tǒng)一,一是存儲(chǔ)統(tǒng)一,不需要有兩個(gè)類型的存儲(chǔ),查詢不需要做拆分。二是任務(wù)開發(fā)統(tǒng)一為 SQL,原先離線是 HiveSQL,實(shí)時(shí)是 Spark Jar 包,統(tǒng)一為 SQL 開發(fā)。數(shù)據(jù)入湖后結(jié)合分布式改造,廣告智能出價(jià)全鏈路由 35 分鐘縮短到 7-10 分鐘。
2、Venus 日志入湖
Venus 是愛(ài)奇藝內(nèi)部的日志分析平臺(tái)。之前的架構(gòu)中 Kafka 數(shù)據(jù)往 ElasticSearch 里面存儲(chǔ),如果業(yè)務(wù)流量較大就給它一個(gè)獨(dú)立集群,小流量業(yè)務(wù)則用公共集群。這個(gè)方案存在一些問(wèn)題:一是流量調(diào)度很難做,當(dāng)集群流量有瓶頸時(shí),需要把流量拆分走;二是 ES 的存儲(chǔ)成本非常高。
存儲(chǔ)改用 Iceberg 方案后,所有業(yè)務(wù)的流量都寫到一個(gè) Iceberg 集群,不需要拆分流量。Venus 接入層通過(guò)日志查詢平臺(tái),數(shù)據(jù)存儲(chǔ)的切換對(duì)用戶是透明的。Iceberg 帶來(lái)的好處包括:
① 成本顯著下降。不需要獨(dú)立的 ES 集群了,Iceberg 和 Trino 都復(fù)用現(xiàn)有的資源,并沒(méi)有什么額外的成本。
② 穩(wěn)定性大幅提升。因?yàn)?ES 的成本太貴,沒(méi)有配副本,一旦單個(gè)磁盤或節(jié)點(diǎn)有問(wèn)題,都會(huì)引發(fā)用戶的報(bào)障。用 Iceberg 以后,寫入帶寬非常大而且穩(wěn)定性很好,報(bào)障減少了 80% 以上。
3、審核場(chǎng)景
接下來(lái)是愛(ài)奇藝內(nèi)部的審核場(chǎng)景,審核場(chǎng)景需要對(duì)一些歷史的行記錄做修改。沒(méi)有 Iceberg 以前,沒(méi)有很好的技術(shù)方案支持行級(jí)更新。
原來(lái)解決方案里用 MongoDB 存全量的數(shù)據(jù),做行級(jí)的更新,然后用 ES 構(gòu)建二級(jí)索引,改用 Iceberg 以后兩個(gè)存儲(chǔ)都統(tǒng)一到 Iceberg 里面。對(duì)業(yè)務(wù)帶來(lái)的好處是:
① 原本的監(jiān)控告警要定期查 ES 做聚合,用 MySQL 開發(fā)報(bào)表,現(xiàn)在不需要了,報(bào)表直接查 Iceberg 就可以,能夠支持實(shí)時(shí)告警。
② 數(shù)據(jù)湖大幅提高業(yè)務(wù)的效率。原本分析任務(wù)開發(fā)非常復(fù)雜,要從 Mongo 里面導(dǎo)數(shù)非常不方便。有了數(shù)據(jù)湖以后可以統(tǒng)一為 SQL 查詢。
4、CDC 訂單入湖
最后是 CDC 類數(shù)據(jù)入湖,此處以訂單為例?;?MySQL 數(shù)據(jù)做大數(shù)據(jù)分析,有兩類解決方案:第一類是每天導(dǎo)出一份到 Hive,缺點(diǎn)是每次導(dǎo)出都是全量,延遲很大,只能看一天以前的數(shù)據(jù)。另外全量導(dǎo)的性能也很差,對(duì) MySQL 壓力也比較大。第二類是實(shí)時(shí)解決方案,增量變更寫在 Kudu 里面,Kudu 是一個(gè)成本很高的解決方案。如果 Kudu 寫入帶寬波動(dòng),同步任務(wù)負(fù)責(zé)人需要去做運(yùn)維操作。
使用數(shù)據(jù)湖方案,愛(ài)奇藝實(shí)時(shí)計(jì)算平臺(tái),通過(guò) Flink CDC 技術(shù)很方便地可以將 MySQL 數(shù)據(jù)入湖。數(shù)據(jù)湖方案具備如下優(yōu)勢(shì),一是近實(shí)時(shí),數(shù)據(jù)延遲在分鐘級(jí),遠(yuǎn)優(yōu)于之前的離線方案;二是成本低,相比于 Kudu 無(wú)需獨(dú)立節(jié)點(diǎn),大幅降低機(jī)器成本;三是省運(yùn)維,Iceberg 寫入帶寬大且穩(wěn)定,大幅降低運(yùn)維代價(jià)。
六、未來(lái)規(guī)劃
最后介紹一下未來(lái)規(guī)劃。愛(ài)奇藝未來(lái)會(huì)在流批一體里面有更多的落地,包括廣告的全面推廣、Pingback 在 BI 場(chǎng)景的落地。另外,我們計(jì)劃把數(shù)據(jù)湖落地在特征生產(chǎn),可以由以前離線或者批的特征生產(chǎn),變成近實(shí)時(shí),能夠支持晚到數(shù)據(jù),支持樣本的行級(jí)的修正。
在技術(shù)方面會(huì)嘗試把 Iceberg 的 Puffin 統(tǒng)計(jì)信息用于查詢加速的場(chǎng)景。還會(huì)對(duì)社區(qū)在做的 Branch 和 Tag 進(jìn)行調(diào)研,尋找內(nèi)部的落地場(chǎng)景。