近期,對 “實時攝取 CDC 數據同步到數據湖” 這一技術主題作了一系列深入的研究和驗證,目前這部分工作已經告一段落,本文把截止目前(2024年5月)的研究結果和重要結論做一下梳理和匯總。為了能給出針對性的技術方案,我們收斂了一下話題,對一些技術選型做了限制,在數據庫這一側,主要以 MySQL 作為示例進行介紹和演示(理論上,PG 等其他主流數據庫均可行),在數據湖這一側,我們重點關注的是 Apache Hudi。
1. 方案架構
這一主題的技術架構基本上可以分為兩個相對獨立的部分:
- 前半程:{ 數據庫 => Kafka } 的 CDC 數據采集
- 后半程:{ Kafka => 數據湖 } 的 CDC 數據寫入
我們認為在鏈路上引入 Kafka 是很有必要的,這在架構上會有很大的彈性和靈活性,所以我們沒有調研從數據庫直接落地到數據庫的相關方案。在這套方案的架構上,有一個顯著的差異,或者說挑戰:不管是前半程還是后半程,都有兩種可能的模式:
- 使用一個作業將整庫 / 多表同步到 Kafka ,以及再使用一個作業讀取 Kafka 數據并同時寫入多張 Hudi 表
- 一張表對應一個作業
如果是單表單作業模式,方案已經已經非常成熟了,但是這種模式不適合大中型場景,應用范圍有限,應該說,最好的實現方式是:多表單作業,但目前來看,這實現起來確實有挑戰,我們后文再詳細介紹。
2. 技術堆棧
從技術選型上看,整個鏈路可能會包含這樣幾類組件:
- CDC 數據采集組件:Flink CDC、Kafka Connect
- Schema Registry組件:Confluent Schema Registry 或 不設置
- Hudi 表數據寫入組件:Flink Hudi Connector、HoodieMultiTableStreamer
除了搭配使用多個開源組件形成一套完整的解決方案外,還有一些一站式的解決方案,例如:阿里云實時計算Flink版的 CDAS 功能,開源工具 Dinky 的 MySQLCDC 整庫到 Hudi 等
3. 關鍵差異
在整個鏈路中,我們需要考慮多個關鍵技術點的實現,評估它們的利弊,這些技術點包括:
- 在 { 數據庫 => Kafka } 的 CDC 數據采集過程中,是一張表對應一個作業,占用一個數據庫鏈接還是整庫 / 多表對應一個作業,占用一個數據庫鏈接?
- 在 { Kafka => 數據湖 } 的 CDC 數據寫入過程中,是一個 Topic 對應一個作業還是多個 Topic 對應一個作業?
- 在整個鏈路中是通過集成一個 Schema Registry 來注冊并獲取每張表的 Schema 信息?還是靠建表語句(Flink SQL)?或是類型推斷?(Spark)
這些關鍵技術點疊加不同的技術組件會形成復雜多樣的技術組合,并各有各的優缺點。
4. 值得期待的方案
個人認為:在僅依賴主流開源產品原生機制和特性的前提下,最值得期待的方案應該是:
Flink CDC ( API 整庫 / 多表同步,分流寫入多個 Topic ,集成 Schema Registry) => Kafka => HoodieMultiTableStreamer => Hudi
前半程的功能除了還不能和 Schema Registry 對接外,其他都已經實現,即使不能自動向 Schema Registry 自動注冊 Schema,還可以手動注冊,這不是一個 Block Issue;后半程的功能其實應該已經支持了,但是,截止當前最新版本 ( Hudi 0.14.1
),HoodieMultiTableStreamer 在處理 Debezium CDC 數據時依然有問題,需要再等待一段時間。
這套方案值得期待的原因在于:后半程 CDC 數據寫入 Hudi 表的工作依賴的是 Hudi 的原生組件 HoodieMultiTableStreamer ,盡管目前它還不成熟,但未來是很值得期待的,這比自己編寫和維護解析 CDC 數據并寫入 Hudi 表要明智的多。至于前半程 Flink CDC 是否會集成 Schema Registry,目前沒有查到確切信息,但如前所述,沒有也不會是很大的問題,無非是手動注冊一個 Schema。不過從長遠來看,Schema Registry 會在實時鏈路中扮演越來越重要的角色。
5. 當前的務實方案
在 HoodieMultiTableStreamer 工具完善之前的這段時間里,個人認為:在不引入任何第三方依賴的前提下,目前最為可靠和實用的解決方案應該是:
Flink CDC ( API 整庫 / 多表同步,分流寫入多個 Topic ) => Kafka => Flink Hudi Connector => Hudi
這一方案的優勢在于:前半程是整庫 / 多表同步,對數據庫影響較小,后半程使用 Flink Hudi Connector 讀取 Kafka 數據寫入 Hudi 表,其中,在創建 Hudi 表時,使用 Flink SQL 的 create table ... with ... like ...
子句可以極大簡化建表語句(建表其實就是提供 Schema 的過程),總體上的代碼量并不大。這個方案不太完美的地方在于:從 Kafka => Hudi 還是要一張表對應一個 Flink 作業,不過,對于一般用戶來說,這未必會帶來很多麻煩。 這一方案具體實現代碼已經在《Flink CDC 整庫 / 多表同步至 Kafka 方案(附源碼)》一文中給出。
此外,關于后半程 { Kafka => Hudi } 的寫入還有一種實現方案:使用 Spark 的 foreachBatch
自行編程實現 Hudi 的多表寫入,各個表的 Hudi 配置也是需要配置文件提供,至于 Schema 信息可以利用 Spark 的 Schema 推斷自動生成,不必顯式配置,但是這種方式多少是有些類型不安全的,本系列文章沒有展開討論,網上有現成方案可供參考。長遠來說,個人還是更看好 HoodieMultiTableStreamer + Confluent Schema Registry 的組合。
6. 具體方案匯總
以下是近期研究和檢驗過的六個主要的解決方案及其它們的優勢、不足和評價:
- 《Flink CDC 整庫 / 多表同步至 Kafka 方案(附源碼)》
- 優勢
- { 數據庫 => Kafka } 只有一個作業,只占用一個連接
- 多表公用一個 Topic 還是 一張表對應一個 Topic 可選
- 使用 Flink SQL 的
create table ... with ... like ...
子句一定程度上簡化了 Hudi 的建表工作
- 不足
- Kafka => Hudi 還是必須要一張表一個 Flink 作業
- 評價
- 實用,但還有提升空間
- 優勢
- 《CDC 實時入湖方案:MySQL > Kafka Connect > Kafka & Schema Registry > Hudi ( Flink Connector ) 》
- 優勢
- 前半程有 Schema Registry 參與,提供 Schema 的注冊、獲取和變更管理
- 不足
- { 數據庫 => Kafka } 和 { Kafka => 數據湖 } 兩端都是一張表一個作業/數據庫連接
- 整體評價
- 整體鏈路完全打通,但只能應用于表數量不多的中小型場景
- 優勢
- 《CDC 實時入湖方案:MySQL > Kafka Connect > Kafka & Schema Registry > Hudi ( HoodieMultiTableStreamer ) 》
- 優勢
- 全程有 Schema Registry 參與,提供 Schema 的注冊、獲取和變更管理
- 不足
- { 數據庫 => Kafka } 是一張表一個作業/數據庫連接
- 目前版本的 HoodieMultiTableStreamer 有缺陷
- 評價
- 整體鏈路尚未完全打通,需要等待 Hudi 的后續版本修復 Bug
- 優勢
- 《CDC 實時入湖方案:MySQL > Flink CDC > Kafka & Schema Registry > Hudi ( Flink Connector ) 》
- 優勢
- 前半程有 Schema Registry 參與,提供 Schema 的注冊、獲取和變更管理
- 不足
- { 數據庫 => Kafka } 和 { Kafka => 數據湖 } 兩端都是一張表一個作業/數據庫連接
- 評價
- 整體鏈路完全打通,但只能應用于表數量不多的中小型場景
- 優勢
- 《CDC 實時入湖方案:MySQL > Flink CDC > Kafka & Schema Registry > Hudi ( HoodieMultiTableStreamer ) 》
- 優勢
- 全程有 Schema Registry 參與,提供 Schema 的注冊、獲取和變更管理
- 不足
- { 數據庫 => Kafka } 是一張表一個作業/數據庫連接
- 目前版本的 HoodieMultiTableStreamer 有缺陷
- 評價
- 整體鏈路尚未完全打通,需要等待 Hudi 的后續版本修復 Bug
- 優勢
- 《CDC 實時入湖方案:MySQL > Flink CDC > Kafka > Hudi》
- 優勢
- 鏈路最簡單,實現起來最容易
- 不足
- { 數據庫 => Kafka } 和 { Kafka => 數據湖 } 兩端都是一張表一個作業/數據庫連接
- 評價
- 整體鏈路完全打通,但只能應用于表數量不多的中小型場景
- 優勢