Flink 流批一體在小米的實踐

阿里雲開發者發表於2022-04-22

簡介:基於流批一體的改造,無論是實時還是離線都只需要維護一套計算框架,為業務開發人員、平臺提供方和計算引擎的支援方節省了大量人力資源。

摘要:本文整理自小米軟體開發工程師金風在 Flink Forward Asia 2021 流批一體專場的演講。本篇內容主要分為三個部分:

  1. 小米的大資料發展演變
  2. 流批一體的平臺建設
  3. 流批一體應用場景
  4. 未來規劃

點選檢視直播回放 & 演講PDF

一、小米的大資料發展演變

 title=

  • 2019 年之前,小米的實時計算主要以 SparkStreaming 為主,少部分 Storm,離線計算以 Spark 為主。
  • 2019 年,開始接入 Flink,並廣泛應用於資訊流搜尋推薦、廣告實時樣本、實時 ETL 等場景,逐步替換了原來的 SparkStreaming 作業,得益於 Flink 框架的各種優秀特性,我們在作業的正確性,實時性,資源使用效率方面都有較大提升。
  • 2020 年,開始接入使用 FlinkSQL,並廣泛用於實時數倉的建設和實時 ETL 作業的開發。FlinkSQL 的實時數倉將資料鏈路由 T+1 降低到了秒級。
  • 2021 年,開始接入資料湖 Iceberg,基於 Flink 和 Iceberg 來構建流批一體的實時數倉解決方案,並在小米內部的部分業務進行了落地,證明流批一體在賦能業務、提升作業開發效率、簡化鏈路節省資源的方面是可行的。

 title=

上圖是小米當前的實時和離線框架,目前是多種框架並存的狀態。業務開發人員無論是寫 SQL 作業還是寫 Jar 包作業,都至少要維護兩套程式碼。公司內部的計算引擎團隊也需要花兩撥人力分別去維護不同的計算框架,同時平臺層也需要對不同的計算引擎去做不同的適配。

 title=

基於流批一體的改造,無論是實時還是離線都只需要維護一套計算框架,為業務開發人員、平臺提供方和計算引擎的支援方節省了一半的人力資源。

二、流批一體的平臺建設

為了探索流批一體,我們也做了很多相關的探索和實踐。

 title=

對於流批一體的平臺化建設,主要分為 4 個方面,分別是後設資料管理、許可權管理、作業排程以及 Flink 的生態建設。

2.1 後設資料管理

 title=

我們基於 Metacat 做了統一的後設資料管理,由 Metacat 統一對接下游不同的儲存系統和上游的計算引擎。

 title=

基於 Metacat,內部的所有系統都被統一劃分成三級結構,與 FlinkSQL 的三級結構相對應。

  • 第一級 Catalog,主要由服務名和叢集名拼接而成。
  • 第二級 Database,它與大部分系統的 Database 保持一致。沒有 Database 的系統預設使用 default 來代替。
  • 第三級 Table,也與系統的 Table 保持一致,比如訊息佇列的 topic 名, Elasticsearch 的索引名。

在構建好統一的後設資料管理之後,只需要寫一條 DML 語句即可完成一個實時將訊息佇列資料入湖作業的開發。

2.2 許可權管理

 title=

在實現了統一的後設資料管理後,在開發 Flink SQL 作業時, 所有系統都被抽象為一個三級的結構表, 業務可以使用三級表名引用任意一個系統的表。同時我們基於 Ranger 也做了統一的許可權管理,在 SQL 層統一管理所有的資源許可權。

我們在計算引擎層做了統一的許可權管理,同時覆蓋了 Flink SQL 和 Flink Jar。Flink SQL 作業可以在生成物理執行計劃時獲取到 SQL 引用的的 Source 和 Sink 表,以及 select 的 Source 表的欄位名。基於以上資訊,即可實現欄位級別的鑑權。同時我們為 Flink Jar 使用者提供了統一的工具類,同時也對接了 Flink Catalog,因此可以做到 Jar 包作業的許可權校驗。

 title=

如上圖所示,統一管理了後設資料和許可權之後,業務開發人員在開發 Flink SQL 作業時就可以非常方便地選擇不同系統的表,包括 Doris、Kudu、Hive 等,作業由後端統一進行提交併鑑權。在作業提交時,我們也能非常方便得獲取到作業的血緣。

2.3 作業排程

 title=

在作業排程方面小米也做了一些嘗試。如上圖左邊這段 SQL,在離線排程模式下它是一個批作業,但在實時排程下它就是一個流作業。在批流混合的排程下,會先啟動批作業,執行完成之後再啟動流作業。

批流混合對於排程器來說是實時的作業。我們主要的改動是在 Flink SQL 的模板作業中先啟動一個 SQL的批作業,執行完成之後再啟動 Flink SQL 的實時作業。

2.4 Flink 的生態建設

 title=

Flink 外掛化的 connector 設計可以非常方便地擴充不同的 connector。無論是 Flink 官方還是其他社群,都提供了非常多的 connector 支援。小米內部也實現了很多種類 connector,只有完善了 Flink 的生態建設,它跨平臺設計的計算能力才能真正體現出來。

 title=

對於 Iceberg connector,社群已經實現了批量讀寫和流式入湖的相關功能。另外流式消費也是一項比較重要的功能,如果不支援流式消費,在數倉的鏈路中就只能改造 ODS 層,下游鏈路只能以批的方式來處理,無法做到全鏈路真正的實時處理。因此支援 Iceberg 的增量消費是實時鏈路中必不可少的一環。

 title=

對於流批一體生態比較重要的還有 Hybrid Source 和 CDC Sink。

Hybrid Source 在社群已經有相關的實現,它能夠將兩種不同的 Source 進行組合,大多陣列合是有限流 + 無限流,這樣就能做到批流混合。

小米在平臺層已經統一管理了所有系統的表,因此在實現 Hybrid Source 時就無需填寫對應表的結構資訊和比較繁瑣的引數資訊,只需要按照順序將需要讀的表名配置在引數中即可,Hybrid Source 會按照配置的順序,依次讀取需要的表。此外,還可以進行不同系統的組合,比較常用的是 MySQL 和訊息佇列的組合,先全量消費 MySQL 中的資料,再增量消費訊息佇列的資料。

 title=

CDC Sink 主要配合 Hybrid Source 來使用。CDC Sink 同樣也對接了內部的 Catalog,它統一管理了 Schema 的變更操作。資料到達下游的 connector 時不需要再去處理繁瑣的 Schema 變更邏輯,只需要將真實的資料以真實的 Schema 寫入對應的系統即可。

無論是 Hybrid Source 還是 CDC Sink,在 Flink 框架層的欄位型別都有一個 barrier 欄位,它可以封裝任意結構的資料,也可以做 Schema 變更。但是一些欄位型別不匹配的情況,只有在執行時才會暴露出來。

三、流批一體應用場景

 title=

大多公司都有資料匯入和匯出的需求,基於 Flink 豐富的生態,我們可以非常方便地實現不同場景的資料整合,主要包括離線整合、實時整合以及批流混合資料整合。

 title=

首先是離線的資料整合。我們使用 Flink SQL Batch 作業替換了之前的 Data X,藉助 Flink 的生態,可以非常方便地實現不同系統資料匯入匯出的需求,也獲得了更豐富的 Source Sink 生態。同時還基於 Flink SQL 可以非常方便地實現欄位的對映,同時 Flink SQL 作為分散式框架,可以很方便提供併發導數的需求。

 title=

其次是實時資料整合,主要分為兩個部分:

  • 第一部分是實時資料的收集,小米內部主要分為兩大類, 分別是日誌資料和 DB 的 Binlog 資料。 這裡主要介紹 DB 系統的 Binlog 資料收集。最初我們使用小米自研的 LCS Binlog 服務來進行統一的 Binlog 收集,類似於 Canal 服務,通過該服務將 Binlog 的資料統一收集到訊息佇列中。
  • 第二部分則是資料的轉儲, 將使用 Spark Streaming 任務將訊息佇列中的資料匯入其他系統,比如 Kudu 或 HDFS。

現在我們使用 Flink 對 Binlog 的收集和轉儲鏈路都進行了改造。使用 Flink CDC 收集 Binlog 資料,並寫入訊息佇列中。同時通過 Flink 將訊息佇列的資料轉儲到其他系統,比如 Kudu、Doris、Iceberg 等等。

 title=

在實際的使用中往往需要用流批混合的方式,以適用不同的場景, 比如分庫分表場景, 部分鏈路重做場景,新增庫表等場景。當前,使用 Flink CDC 任務來收集庫級別的 Binlog 資料,如果按照表級別來進行收集,會對 MySQL 服務造成較大的壓力。將資料收集到訊息佇列後,再針對不同的收集場景,起不同的作業來進行轉儲。

Flink CDC 收集的資料是庫級別,當某張表的資料需要重做時,無法將庫級別的資料重做,因為這樣會影響到其他的表。所以,對於單表的全量資料,我們會直接從 MySQL 讀取,再從訊息佇列中讀取增量的資料,因此這裡需要用 Hybrid Source 分別讀取 MySQL 和訊息佇列中的資料。

 title=

另一種批流混合的資料整合場景則是批作業和流作業混合使用。

在支援 TiDB 的資料收集和轉儲時,我們無法使用 Hybrid Source,因為 TiDB 的全量資料往往非常大,我們需要起大量併發能夠加速全量資料的轉儲,而增量資料則只需要較小併發即可。在全量資料部分我們使用 Flink SQL Batch 作業來完成, 可以靈活調整併發,且相對於實時作業處理效率更高,增量部分則以較小的併發能轉儲即可。

 title=

另外一個比較重要的業務場景是實時數倉的構建。在小米內部也經歷了從傳統離線數倉到 Lambda 架構再到當前基於資料湖的實時實倉。這三種場景有不同的優缺點,會應用於不同的業務場景。有兩個比較典型的案例,分別是小米手機啟用統計以及小米銷售服務實時數倉。

 title=

上圖是小米手機啟用業務流程,首先是啟用資料的收集,通過不同的渠道來收集日誌,並進行統一的彙總和清洗。通過採集資料配合維表 join 能夠檢測到提前啟用的 case,同時也能夠基於一些維度資料進行資料清洗,判斷出哪些屬於自然啟用,哪些屬於正常的活躍日誌。

 title=

小米手機啟用數倉的整體架構涉及到實時鏈路和離線鏈路,這裡主要介紹實時鏈路。我們採用的維度表主要是 HBase 和 FileSystem,HBase 用於儲存歷史全量的唯一 ID,Hive 主要儲存少量的維度資料,最終的結果會實時落到 Kudu 中,業務就可以通過 OLAP 引擎查到實時的啟用資料。同時離線鏈路也是必不可少的,實時和離線產生的資料整體的重合率達到 99.94%。

上述鏈路中最關鍵的點是需要使用 HBase 來儲存歷史的全量 ID 來去重。這其中 join 歷史全量資料 HBase 表是最關鍵的地方,最開始我們使用同步的 lookup join 方式,但是遇到了較大的效能瓶頸,後改用非同步 join 方式,最終整體的處理速度有了數十倍的提升。

 title=

小米的銷售服務涉及到多個模組,包括訂單、物流、商品、售後門店,在構建過程中我們也遇到了非常多的問題,最終證明基於 Flink SQL 改造離線鏈路構建實時數倉的方案是可行的。

 title=

上圖是銷售服務數倉的整體架構,銷售服務用到的維度表主要來自於訊息佇列和 FileSystem。在銷售服務的場景下,無論是訂單表還是商品類目表都會實時更新。進行關聯時,無論哪一條流有更新,結果都需要更新。因此銷售的服務數倉大多采用雙流 join,而雙流 join 伴隨而來的就是狀態問題。

在 Flink SQL 中我們無法準確控制某個運算元的狀態過期的策略,因此只能設定一個統一的狀態過期時間,如果一段時間內某些狀態沒有被訪問則會被清理,但這個場景是有侷限性的,針對於物流售後這些場景,單條記錄在整個實時流中的週期可能會超過一個月,但一般情況下我們無法將 Flink 作業的狀態超時時間設定為一個月,產生的狀態量太多會導致處理效率變低,也不利於作業鏈路的回溯。一旦作業出現問題,上游的資料都需要重做,訊息佇列中大多資料儲存不會超過 7 天。

在銷售服務的某些場景中中,我們引入了離線作業,根據結果表的資料,獲取狀態還未結束的資料,將對應的維度資料寫回到實時流中, 確保這些維度資料不會過期, 當主表的資料到達 join 運算元,就可以得到正確的資料, 即使主表的某條記錄超過一個月才出現變更。

 title=

上圖是小米 APP 近實時數倉的架構。通過採集日誌模組將日誌統一收集到訊息佇列中。由於是日誌資料,只需要使用到 Iceberg v1 表,中間的 DWD 和 DM 層都使用 Flink SQL 進行實時消費和處理,然後寫入到 Iceberg v2 表中。

對於有些需要儲存歷史的全量資料並保證資料準確性,但對時效性要求不高的資料表,我們採用離線的處理思路,基於 DWD 層進行離線處理。每天使用 t-1 的資料去修正 t-2 的資料,通過不斷修正歷史資料,可以很大程度地保證這些表的準確率。

 title=

對於一些舊的鏈路或者上游資料由其他業務方提供,且短期內無法修改且無法產生 CDC 資料的系統,我們採用了 Spark Merge Into 作業定時排程來產生增量的資料,並實時寫入到 Iceberg v2 表中。在生產實踐中,通過 Merge Into 產生的資料延遲大概是 5~8 分鐘,後面鏈路的延遲都可以控制在分鐘級以內,因此全鏈路的延遲基本可以控制在 10 分鐘之內,相比之前 t+1 的延遲有了巨大的提升。

 title=

對於能夠從源頭產生 CDC 資料的系統,我們會將實時資料寫入到訊息佇列中,然後實時入湖。整體架構如上圖所示,實時部分主要用使用 Flink 和訊息佇列的組合來達到秒級的延遲,再將訊息佇列的資料 Sink 到 Iceberg 中,用於 Query 查詢。同時下游有一條離線鏈路不斷通過 Merge Into 進行修正,保證 Iceberg 中結果的正確性。

整個鏈路基於訊息佇列保證了全鏈路的時效性,同時基於資料湖保證了 Query 的查詢時效,另外通過離線的 Merge Into 不斷地修正,保證了最終結果的準確性。

雖然數倉的架構整體都基本類似,但是針對不同業務場景及不同的需求,實際的鏈路複雜度還是有較大的區別。因此在使用 Flink 構建數倉時,一定要結合實際的需求選擇合理的方案。

四、未來規劃

當前 Flink + Iceberg 的資料湖解決方案在小米已經初步落地,未來我們可以提升的空間依然非常大,我們會不斷跟進社群,繼續推進小米內部流批一體化的建設。

 title=

後續我們會將 Flink SQL Batch 用於更加複雜的場景。當前 Flink SQL Batch 發揮的場景有限,主要運用於批量匯出的場景,相信未來它會發揮更大的價值。

其次,我們會跟進社群的 built in dynamic table [1],結合訊息佇列和資料湖,兼顧時效性和準確性,提升使用者的體驗。

同時我們也會升級 Hybrid Source connector,當前社群的 Hybrid Source 是適配最新版的 Source 介面,新版的 Source 介面在對接其他系統時靈活度更高。

[1] https://cwiki.apache.org/confluence/display/Flink/FLIP-188%3A+Introduce+Built-in+Dynamic+Table+Storage


點選檢視直播回放 & 演講PDF

版權宣告:本文內容由阿里雲實名註冊使用者自發貢獻,版權歸原作者所有,阿里雲開發者社群不擁有其著作權,亦不承擔相應法律責任。具體規則請檢視《阿里雲開發者社群使用者服務協議》和《阿里雲開發者社群智慧財產權保護指引》。如果您發現本社群中有涉嫌抄襲的內容,填寫侵權投訴表單進行舉報,一經查實,本社群將立刻刪除涉嫌侵權內容。

相關文章