Flink 如何通過2PC實現Exactly-once語義 (原始碼分析)

ljygz 發表於 2022-01-26
Flink

Flink通過全域性快照能保證內部處理的Exactly-once語義

但是端到端的Exactly-once還需要下游資料來源配合,常見的通過冪等或者二階段提交這兩種方式保證

這裡就來分析一下Sink二階段提交的Flink原始碼是如何實現的

本文原始碼基於Flink1.14

老版本的話看TwoPhaseCommitSinkFunction,現在用SinkWriter邏輯都是差不多的

先來看下我們的主角  org.apache.flink.streaming.runtime.operators.sink.SinkOperator 類

1階段. 在barrier到齊準備觸發checkpoint之前

Flink 如何通過2PC實現Exactly-once語義 (原始碼分析)

呼叫了資料來源的預提交方法 prepareCommit

來看下已kafka為例具體做了什麼

Flink 如何通過2PC實現Exactly-once語義 (原始碼分析)

 kafkaWriter就是呼叫了生產者的flush方法,在已經開始的事務裡面刷資料

2階段. 觸發checkpoint儲存狀態資料的時候 snapshotState 方法

Flink 如何通過2PC實現Exactly-once語義 (原始碼分析)

 以kafka為例

Flink 如何通過2PC實現Exactly-once語義 (原始碼分析)

 會啟動下一個checkpoint的kafka事務,直接就begin事務了,接著

Flink 如何通過2PC實現Exactly-once語義 (原始碼分析)

用這次checkpoint需要commit的kafkaCommiter更新了狀態, 會被儲存下來,這裡有事務資訊的後面會用到

3階段. 當checkpoint完成以後

Flink 如何通過2PC實現Exactly-once語義 (原始碼分析)

 已kafka為例,會直接提交事務了commit

Flink 如何通過2PC實現Exactly-once語義 (原始碼分析) 

這裡可能會有疑問,,如果我只預提交了,還沒有commit這時候跪了,那我從checkpoint恢復起來,那不就有問題了嗎

帶著疑問看下最後一個階段

4階段. 當任務失敗從checkpoint恢復的時候

初始化的時候會恢復狀態

Flink 如何通過2PC實現Exactly-once語義 (原始碼分析)

Flink 如何通過2PC實現Exactly-once語義 (原始碼分析)

可以看到會將上面說的上次checkpoint需要commiter的放到recoveredCommittables恢復佇列裡面

然後retrayWithDelay,就會根據我們儲存的kafka事務資訊id等去判斷,上一次事務的狀態,如果是預提交的話,就會先去commit了

總結一下流程:

prepareSnapshotPreBarrier快照觸發前, 預提交事務,kafka裡面就是flash
snapshotState快照儲存時,開啟一個新的事務kafka就是beginTransation,並且儲存這次要提交的事務資訊
notifyCheckpointComplete快照完成以後,呼叫對應的commit提交事務 , kafka就是commitTransation
initializeState從快照恢復,會先判斷上次事務的狀態如果還沒提交會先提交