在學習flink的時候看了本書《Stream Processing with Apache Flink》宪睹。里面對Flink checkpoint的原理講得挺清楚的愁茁,后面內部分享時也參考了這個說法,所以這里按照我的理解描述一下亭病。
首先鹅很,flink的checkpoint并不是將Subtask或者UDF對象進行序列化,然后保存罪帖。他們確實實現(xiàn)了Serializable接口促煮,但是是為了要在Client,JobManager和TaskManager之間傳輸Graph整袁。最終被checkpoint保存的每個subtask的狀態(tài)只有raw state和managed state兩種菠齿。raw state是用戶自己進行序列化,而managed state是在operator生命周期初始化時就被注冊到backend storage對象中了坐昙,在進行checkpoint時绳匀,會直接拿到注冊的state進行保存(中間會調用回調函數(shù),在UDF中對state進行賦值)炸客。所以checkpoint的state不是很大的數(shù)據(jù)疾棵。
其次,checkpoint要保存的每個subtask的state并不是自然時刻下痹仙,他們的state是尔。如下圖所示,并不是要將Source1的3开仰,Source2的4拟枚,Task1的2薪铜,Task2的3保存下來。如果要這樣保存的話梨州,那么on-the-fly的數(shù)據(jù)也要保存痕囱,否則無法從checkpoint中還原這個瞬間。checkpoint真正要保存的時刻是指的flink processing time或者event time概念下的瞬間暴匠。很顯然鞍恢,圖中的這個瞬間至少Source和Task是不在一個“時刻”的,因為Source1的“時間”顯然晚于Task1的“時間”每窖。
Easy Understand
在理想情況下帮掉,checkpoint主要是完成一下這幾個動作:
- 暫停新數(shù)據(jù)的輸入
- 等待流中on-the-fly的數(shù)據(jù)被處理干凈,此時得到flink graph的一個snapshot
- 將所有Task中的State拷貝到State Backend中窒典,如HDFS蟆炊。此動作由各個Task Manager完成
- 各個Task Manager將Task State的位置上報給Job Manager,完成checkpoint
- 恢復數(shù)據(jù)的輸入
如上所述瀑志,這里才需要“暫停輸入+排干on-the-fly數(shù)據(jù)”的操作涩搓,這樣才能拿到同一時刻下所有subtask的state。這又必然引入了STW的副作用劈猪。
Chandy-Lamport algorithm
于是有了Chandy-Lamport算法昧甘。他解決的問題,就是在不停止流處理的前提下拿到每個subtask在某一瞬間的snapshot战得,從而完成checkpoint充边。
- 在checkpoint觸發(fā)時刻,Job Manager會往所有Source的流中放入一個barrier(圖中三角形)常侦。barrier包含當前checkpoint的ID
- 當barrier經過一個subtask時浇冰,即表示當前這個subtask處于checkpoint觸發(fā)的“時刻”,他就會立即將barrier法往下游聋亡,并執(zhí)行checkpoint方法將當前的state存入backend storage肘习。圖中Source1和Source2就是完成了checkpoint動作。
- 如果一個subtask有多個上游節(jié)點坡倔,這個subtask就需要等待所有上游發(fā)來的barrier都接收到漂佩,才能表示這個subtask到達了checkpoint觸發(fā)“時刻”。但所有節(jié)點的barrier不一定一起到達致讥,這時候就會面臨“是否要對齊barrier”的問題(
Barrier Alignment
)仅仆。如圖中的Task1.1器赞,他有2個上游節(jié)點垢袱,Source1和Source2。假設Source1的barrier先到港柜,這時候Task1.1就有2個選擇:- 是馬上把這個barrier發(fā)往下游并等待Source2的barrier來了再做checkpoint
- 還是把Source1這邊后續(xù)的event全都cache起來请契,等Source2的barrier來了咳榜,在做checkpoint,完了再繼續(xù)處理Source1和Source2的event爽锥,當前Source1這邊需要先處理cache里的event涌韩。
這引入了另一個概念:Result guarantees。
Result Guarantees
Flink提供了幾種容錯機制:
- At-Most-Once
- At-Least-Once
- Exactly-Once
- End-to-end Exactly-Once
當不采用checkpoint時氯夷,每個event做多就只會被處理一次臣樱,這就是At-Most-Once
。
當不開啟Barrier對齊時腮考,上圖中的Source1來的在barrier后面的一些event有可能比Source2的barrier要先到Task1.1雇毫,因為我們沒有cache這些event,所以他們會正常被處理并有可能更新Task1.1的state踩蔚。這樣棚放,在回復checkpoint后,Task1.1的state可能就是處理了某些checkpoint“時刻”之后數(shù)據(jù)的狀態(tài)馅闽。但是對于Source1來說飘蚯,他還是會offset到正常的checkpoint“時刻”的位置,那么之前處理過的barrier后面的event可能還是會被再次放入這個流中福也。那么這些event就不能保證“只處理一次”了局骤,有可能處理多次,這就是At-Least-once
拟杉。
如果在Task1.1.處庄涡,先來的barrier后面的event都被cache了,那么就不會影響到這個task的state搬设。那么Task1.1的checkpoint的state就能準確反映checkpoint“時刻”的情況穴店。那么checkpoint回復后也不會有前面說的問題,這就是Exactly-Once
拿穴。但是因為Exactly-Once引入了cache機制泣洞,這會給checkpoint動作帶來額外的時延(latency)。
End-to-end Exactly-Once
需要結合外部系統(tǒng)一起完成默色,這里就不做討論了球凰。