Flink CDC MongoDB Connector 的實現原理和使用實踐

ApacheFlink發表於2022-06-27

本文整理自 XTransfer 資深 Java 開發工程師、Flink CDC Maintainer 孫家寶在 Flink CDC Meetup 的演講。主要內容包括:

  1. MongoDB Change Stream 技術簡介
  2. MongoDB CDC Connector 業務實踐
  3. MongoDB CDC Connector 生產調優
  4. MongoDB CDC Connector 並行化 Snapshot 改進
  5. 後續規劃

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

一、MongoDB Change Stream 技術簡介

img

MongoDB 是一種面向文件的非關係型資料庫,支援半結構化資料儲存;也是一種分散式的資料庫,提供副本集和分片集兩種叢集部署模式,具有高可用和水平擴充套件的能力,比較適合大規模的資料儲存。另外, MongoDB 4.0 版本還提供了多文件事務的支援,對於一些比較複雜的業務場景更加友好。

img

MongoDB 使用了弱結構化的儲存模式,支援靈活的資料結構和豐富的資料型別,適合 Json 文件、標籤、快照、地理位置、內容儲存等業務場景。它天然的分散式架構提供了開箱即用的分片機制和自動 rebalance 能力,適合大規模資料儲存。另外, MongoDB 還提供了分散式網格檔案儲存的功能,即 GridFS,適合圖片、音訊、視訊等大檔案儲存。

img

MongoDB 提供了副本集和分片集兩種叢集模部署模式。

副本集:高可用的部署模式,次要節點通過拷貝主要節點的操作日誌來進行資料的複製。當主要節點發生故障時,次要節點和仲裁節點會重新發起投票來選出新的主要節點,實現故障轉移。另外,次要節點還能分擔查詢請求,減輕主要節點的查詢壓力。

分片集:水平擴充套件的部署模式,將資料均勻分散在不同 Shard 上,每個 Shard 可以部署為一個副本集,Shard 中主要節點承載讀寫請求,次要節點會複製主要節點的操作日誌,能夠根據指定的分片索引和分片策略將資料切分成多個 16MB 的資料塊,並將這些資料塊交給不同 Shard 進行儲存。Config Servers 中會記錄 Shard 和資料塊的對應關係。

img

MongoDB 的 Oplog 與 MySQL 的 Binlog 類似,記錄了資料在 MongoDB 中所有的操作日誌。Oplog 是一個有容量的集合,如果超出預設的容量範圍,則會丟棄先前的資訊。

img

與 MySQL 的 Binlog 不同, Oplog 並不會記錄變更前/後的完整資訊。遍歷 Oplog 的確可以捕獲 MongoDB 的資料變更,但是想要轉換成 Flink 支援的 Changelog 依然存在一些限制。

首先,訂閱 Oplog 難度較大。每個副本集會維護自己的 Oplog, 對於分片叢集來說,每個 Shard 可能是一個獨立的副本集,需要遍歷每個 Shard 的 Oplog 並按照操作時間進行排序。另外, Oplog 沒有包含變更文件前和變更後的完整狀態,因此既不能轉換成 Flink 標準的 Changelog ,也不能轉換成 Upsert 型別的 Changelog 。這亦是我們在實現 MongoDB CDC Connector 的時候沒有采用直接訂閱 Oplog 方案的主要原因。

img

最終我們選擇使用 MongoDB Change Streams 方案來實現 MongoDB CDC Connector。

Change Streams 是 MongoDB 3.6 版本提供的新特性,它提供了更簡單的變更資料捕獲介面,遮蔽了直接遍歷 Oplog 的複雜度。Change Streams 還提供了變更後文件完整狀態的提取功能,可以輕鬆轉換成 Flink Upsert 型別的 Changelog。它還提供了比較完整的故障恢復能力,每一條變更記錄資料都會包含一個 resume token 來記錄當前變更流的位置。故障發生後,可以通過 resume token 從當前消費點進行恢復。

另外, Change Streams 支援變更事件的篩選和定製化的功能。比如可以將資料庫和集合名稱的正則過濾器下推到 MongoDB 來完成,可以明顯減少網路開銷。它還提供了對集合庫以及整個叢集級別的變更訂閱,能夠支援相應的許可權控制。

img

使用 MongoDB Change Streams 特性實現的 CDC Connector 如上圖所示。首先通過 Change Streams 訂閱 MongoDB 的變更。比如有 insert、update、delete、replace 四種變更型別,先將其轉換成 Flink 支援的 upsert Changelog,便可以在其之上定義成一張動態表,使用 Flink SQL 進行處理。

目前 MongoDB CDC Connector 支援 Exactly-Once 語義,支援全量加增量的訂閱,支援從檢查點、儲存點恢復,支援 Snapshot 資料的過濾,支援資料庫的 Database、Collection 等後設資料的提取,也支援庫集合的正則篩選功能。

二、MongoDB CDC Connector 業務實踐

img

XTransfer 成立於 2017 年,聚焦於 B2B 跨境支付業務,為從事跨境電商出口的中小微企業提供外貿收款以及風控服務。跨境 B 類業務結算場景涉及的業務鏈路很長,從詢盤到最終的成交,過程中涉及物流條款、支付條款等,需要在每個環節上做好風險管控,以符合跨境資金交易的監管要求。

以上種種因素對 XTransfer 的資料處理安全性和準確性都提出了更高的要求。在此基礎上,XTransfer 基於 Flink 搭建了自己的大資料平臺,能夠有效保障在跨境 B2B 全鏈路上的資料能夠被有效地採集、加工和計算,並滿足了高安全、低延遲、高精度的需求。

img

變更資料採集 CDC 是資料整合的關鍵環節。在沒有使用 Flink CDC 之前,一般使用 Debezium、Canal 等傳統 CDC 工具來抽取資料庫的變更日誌,並將其轉發到 Kafka 中,下游讀取 Kafka 中的變更日誌進行消費。這種架構存在以下痛點:

  • 部署元件多,運維成本較高;
  • 下游資料消費邏輯需要根據寫入端進行適配,存在一定的開發成本;
  • 資料訂閱配置較複雜,無法像 Flink CDC 一樣僅通過 SQL 語句便定義出一個完整的資料同步邏輯;
  • 難以全部滿足全量 + 增量採集,可能需要引入 DataX 等全量採集元件;
  • 比較偏向於對變更資料的採集,對資料的處理過濾能力較為薄弱;
  • 難以滿足異構資料來源打寬的場景。

目前我們的大資料平臺主要使用 Flink CDC 來進行變更資料捕獲,它具有如下優勢:

1. 實時資料整合

img

  • 無須額外部署 Debezium、Canal、Datax 等元件,運維成本大幅降低;
  • 支援豐富的資料來源,也可複用 Flink 既有的 connectors 進行資料採集寫入,可以覆蓋大多數業務場景;
  • 降低了開發難度,僅通過 Flink SQL 就可以定義出完整的資料整合工作流程;
  • 資料處理能力較強,依託於 Flink 平臺強大的計算能力可以實現流式 ETL 甚至異構資料來源的 join、group by 等。

2. 構建實時數倉

img

  • 大幅簡化實時數倉的部署難度,通過 Flink CDC 實時採集資料庫的變更,並寫入 Kafka、Iceberg、Hudi、TiDB 等資料庫中,即可使用 Flink 進行深度的資料探勘和資料處理。
  • Flink 的計算引擎可以支援流批一體的計算模式,不用再維護多套計算引擎,可以大幅降低資料的開發成本。

3. 實時風控

img

  • 實時風控以往一般採取往 Kafka 中發業務事件的方式實現,而使用 Flink CDC 之後,可以直接從業務庫中捕獲風控事件,然後通過 Flink CDC 來進行復雜的事件處理。
  • 可以執行模型,以通過 Flink ML、Alink 來豐富機器學習的能力。最後將這些實時風控的處置結果回落進 Kafka,下達風控指令。

三、MongoDB CDC Connector 生產調優

img

MongoDB CDC Connector 的使用有如下幾點要求:

  • 鑑於使用了 Change Streams 的特性來實現 MongoDB CDC Connector, 因此要求 MongoDB 的最小可用版本是 3.6,比較推薦 4.0.8 及以上版本。
  • 必須使用叢集部署模式。由於訂閱 MongoDB 的 Change Streams 要求節點之間能夠進行相互複製資料,單機 MongoDB 無法進行資料的互相拷貝,也沒有 Oplog,只有副本集或分片集的情況下才有資料複製機制。
  • 需要使用 WireTiger 儲存引擎,使用 pv1 複製協議。
  • 需要擁有 ChangeStream 和 find 使用者許可權。

img

使用 MongoDB CDC Connector 時要注意設定 Oplog 的容量和過期時間。MongoDB oplog 是一個特殊的有容量集合,容量達到最大值後,會丟棄歷史資料。而 Change Streams 通過 resume token 來進行恢復,太小的 oplog 容量可能會導致 resume token 對應的 oplog 記錄不再存在,即 resume token 過期,進而導致 Change Streams 無法被恢復。

可以使用 replSetResizeOplog 設定 oplog 容量和最短保留時間,MongoDB 4.4 版本之後也支援設定最小時間。一般而言,生產環境中建議 oplog 保留不小於 7 天。

img

對一些變更較慢的表,建議在配置中開啟心跳事件。變更事件和心跳事件可以同時向前推進 resume token,對於變更較慢的表,可以通過心跳事件來重新整理 resume token 避免其過期。

可以通過 heartbeat.interval.ms 設定心跳的間隔。

img

由於只能將 MongoDB 的 Change Streams 轉換成 Flink 的 Upsert changelog,它類似於 Upsert Kafka 形式,為了補齊 –U 前置映象值,會增加一個運算元 ChangelogNormalize,而這會帶來額外的狀態開銷。因此在生產環境中比較推薦使用 RocksDB State Backend。

img

當預設連線的引數無法滿足使用需求時,可以通過設定 connection.options 配置項來傳遞 MongoDB 支援的連線引數。

比如連線 MongoDB 的使用者建立的資料庫不在 admin 中,可以設定引數來指定需要使用哪個資料庫來認證當前使用者,也可以設定連線池的最大連線引數等,MongoDB 的連線字串預設支援這些引數。

img

正則匹配多庫、多表是 MongoDB CDC Connector 在 2.0 版本之後提供的新功能。需要注意,如果資料庫名稱使用了正則引數,則需要擁有 readAnyDatabase 角色。因為 MongoDB 的 Change Streams 只能在整個叢集、資料庫以及 collection 粒度上開啟。如果需要對整個資料庫進行過濾,那麼資料庫進行正則匹配時只能在整個叢集上開啟 Change Streams ,然後通過 Pipeline 過濾資料庫的變更。可以通過在 Ddatabase 和 Collection 兩個引數中寫入正規表示式進行多庫、多表的訂閱。

四、MongoDB CDC Connector 並行化 Snapshot 改進

img

為了加速 Snapshot 的速度,可以使用 Flip-27 引入的 source 來進行並行化改造。首先使用一個 split 列舉器,根據一定的切分策略,將一個完整的 Snapshot 任務拆分成若干個子任務,然後分配給多個 split reader 並行做 Snapshot ,以此提升整體任務的執行速度。

但是在 MongoDB 裡,大多情況下元件是 ObjectID,其中前面四個位元組是 UNIX 描述,中間五個位元組是一個隨機值,後面三個位元組是一個自增量。在相同描述裡插入的文件並不是嚴格遞增的,中間的隨機值可能會影響區域性的嚴格遞增,但從總體來看,依然能夠滿足遞增趨勢。

因此,不同於 MySQL 的遞增元件,MongoDB 並不適合採用 offset + limit 的切分策略對其集合進行簡單拆分,需要針對 ObjectID 採用針對性的切分策略。

img

最終,我們採取了以下三種 MongoDB 切分策略:

  • Sample 取樣分桶:原理是利用 $sample 命令對 collection 進行隨機取樣,通過平均文件大小和每個 chunk 的大小來預估需要的分桶數。要求相應集合的查詢許可權,其優點是速度較快,適用於資料量大但是沒有分片的集合;缺點是由於使用了抽樣預估模式,分桶的結果不能做到絕對均勻。
  • SplitVector 索引切分:SplitVector 是 MongoDB 計算 chunk 分裂點的內部命令,通過訪問指定的索引計算出每個 chunk 的邊界。要求擁有 SplitVector 許可權,其優點是速度快,chunk 結果均勻;缺點是對於資料量大且已經分片的集合,不如直接讀取 config 庫中已經分好的 chunks 後設資料。
  • Chunks 後設資料讀取:因為 MongoDB 在 config 資料庫會儲存分片集合的實際分片結果,因此可以直接從 config 中讀取分片集合的實際分片結果。要求擁有 config 庫讀取許可權,僅限於分片集合使用。其優點是速度快,無須重新計算 chunk 分裂點,chunk 結果均勻,預設情況下為 64MB;缺點是不能滿足所有場景,僅限分片場景。

img

上圖為 sample 取樣分桶示例。左側是一個完整的集合,從完整的集合中設定樣本數量,然後將整個樣本縮小,並根據取樣以後的樣本進行分桶,最終結果就是我們希望的 chunks 邊界。

sample 命令是 MongoDB 取樣的一個內建命令。在樣本值小於 5% 的情況下,使用偽隨機演算法進行取樣;樣本值大於 5% 的情況下,先使用隨機排序,然後選擇前 N 個文件。它的均勻度和耗時主要取決於隨機演算法和樣本的數量,是一種均勻程度和切分速度的折中策略,適合於要求切分速度快,但可以容忍切分結果不太均勻的場景。

在實際測試中,sample 取樣的均勻程度有著不錯的表現。

img

上圖為 SplitVector 索引切分示例。左側是原始集合,通過 SplitVector 命令指定需要訪問的索引,為 ID 索引。可以設定每個 chunk 的大小,單位為 MB,然後使用 SplitVector 命令訪問索引,並通過索引計算每個塊的邊界。

它速度快,chunk 結果也很均勻,適用於大部分場景。

img

上圖為 config.chuncks 讀取示例,即直接讀取 MongoDB 已經分好的 chunks 後設資料。在 Config Server 中會儲存每個 Shard、其所在機器以及每個 Shard 的邊界。對於分片集合,可以直接在 chunks 中讀取它的邊界資訊,無須重複計算這些分裂點,也可以保證每一個 chunk 的讀取在單臺機器上就能完成,速度極快,在大規模的分片集合場景下有著很好的表現。

五、後續規劃

img

Flink CDC 的後續規劃主要分為以下五個方面:

  • 第一,協助完善 Flink CDC 增量 Snapshot 框架;
  • 第二,使用 MongoDB CDC 對接 Flink CDC 增量 Snapshot 框架,使其能夠支援並行 Snapshot 改進;
  • 第三,MongoDB CDC 支援 Flink RawType。對於一些比較靈活的儲存結構提供 RawType 轉換,使用者可以通過 UDF 的形式對其進行自定義解析;
  • 第四,MongoDB CDC 支援從指定位置進行變更資料的採集;
  • 第五,MongoDB CDC 穩定性的優化。

問答

Q:MongoDB CDC 延遲高嗎?是否需要通過犧牲效能來降低延遲?

A:MongoDB CDC 延遲不高,在全量採集的時候經過 changelog normalize 可能會對於 CDC 的增量採集造成一些背壓,但是這種情況可以通過 MongoDB 並行化改造、增加資源的方式來避免。

Q:預設連線什麼時候無法滿足要求?

A:MongoDB 的使用者可以在任何資料庫、任何子庫中進行建立。如果不是在 admin 的資料庫中建立使用者,認證的時候需要顯示地指定要在哪個資料庫中認證使用者,也可以設定最大的連線大小等引數。

Q:MongoDB 目前的 DBlog 支援無鎖併發讀取嗎?

A:DBlog 的無鎖併發擁有增量快照的能力,但是因為 MongoDB 難以獲取當前 changelog 的位點,所以增量快照無法立刻實現,但無鎖併發的 Snapshot 即將支援。


更多 Flink 相關技術問題,可掃碼加入社群釘釘交流群
第一時間獲取最新技術文章和社群動態,請關注公眾號~

img

活動推薦

阿里雲基於 Apache Flink 構建的企業級產品-實時計算Flink版現開啟活動:
99 元試用 實時計算Flink版(包年包月、10CU)即有機會獲得 Flink 獨家定製衛衣;另包 3 個月及以上還有 85 折優惠!
瞭解活動詳情:https://www.aliyun.com/produc...

image.png

相關文章