一、背景
目前 yarn 集群 360 個FLink實時作業,90% 都是使用 flink1.13.3 + cdc2.1 ,在12月17號發現一個流任務:xxx_mysql_kafka 運行無異常,但是一直不往 Kafka 發送最新數據
二、問題排查
1、 根據該任務 application id 查看具體運行在那個 yarn 節點上
- 堡壘機登錄該節點,切換到 yarn 用戶下,使用 jstat -gcutl pid 查看該 jvm 進程,發現頻繁 young gc 且 full gc 次數過多,達到 30 次
查看到 FUll GC 非常頻繁
- 使用 jmap 將該 jvm 進程的 heap 內存 dump 下來,用 mat 進行分析:/usr/java/jdk1.8.0_144/bin/jmap -dump:format=b,file=3512.hprof 3512,將 dump 文件導入 mat 中
- 根據 mat 提示信息,定位問題代碼,發現出現問題的對象是 ResultSetImpl ,這是從 MySQL 讀取數據用到的對象。
使用 idea 打開 flink-cdc-connector 的代碼,分支切換到 release-2.1 ,查看 MySqlSnapshotSplitReadTask 類的代碼,問題出現下面這一段代碼,flink-cdc 從 MySQL 讀取數據,然后發送到下游,異常的是這一批次讀取出來的對象有 50w+ 條,這應該是出問題的具體原因
5、排查這一批次分片讀取 50W 數據的原因,任務啟動時設置的 chunk.size 為 2w,理論上應該每批次讀取 2w 才對,查看 flink-cdc 源碼,具體的分片操作在 ChunkSplitter類的 splitTableIntoChunks 函數
因為抽取的表主鍵類型是 bigint ,所以觸發了 flink-cdc 的分片優化邏輯,雖然我們配置的 chunk.size 是 2w,但是經過 flink-cdc 內部優化,優化后的 chunk.size 為 2w * 120 = 240w 左右
具體的分片優化邏輯如下:
a. 計算該表數據的分布因子:最大主鍵id - 最小主鍵 id = 主鍵最大最小差
b. 主鍵最大最小差 / 該表數據量 = 數據分布因子
c. 數據分布因子 * 任務啟動輸入的 chunk.size = 優化后的分片大小
出問題表的計算過程:(202112061064180438(最大主鍵) - 202112061000977284(最小主鍵) / 529696(該表數據量) = 119.3197(數據分布因子),最終的分片大小為 119.3197*2w = 240w,
因為該表數據的最大id與最小id差值較大,但是該表數據量只有 50w+,導致 flink-cdc 做了一個反向優化,最后出問題了
查看該任務的 jobmnager 日志,驗證了上面的猜測,該表的最終分片大小為:2443667
-
出現問題的具體原因已經找到,解決方案
a. 降低 split-key.even-distribution.factor.upper-bound 比例,默認為 1000,可調至 10,這樣最大批次的數據量為 10*chunk.size b. 不使用增量抽數模式:snapshot :scan.incremental.snapshot.enabled = false