Flink Checkpoint

在學習flink的時候看了本書《Stream Processing with Apache Flink》。裏面對Flink checkpoint的原理講得挺清楚的,後面內部分享時也參考了這個說法,所以這裏按照我的理解描述一下。

首先,flink的checkpoint並不是將Subtask或者UDF對象進行序列化,然後保存。他們確實實現了Serializable接口,但是是爲了要在Client,JobManager和TaskManager之間傳輸Graph。最終被checkpoint保存的每個subtask的狀態只有raw state和managed state兩種。raw state是用戶自己進行序列化,而managed state是在operator生命週期初始化時就被註冊到backend storage對象中了,在進行checkpoint時,會直接拿到註冊的state進行保存(中間會調用回調函數,在UDF中對state進行賦值)。所以checkpoint的state不是很大的數據。

其次,checkpoint要保存的每個subtask的state並不是自然時刻下,他們的state。如下圖所示,並不是要將Source1的3,Source2的4,Task1的2,Task2的3保存下來。如果要這樣保存的話,那麼on-the-fly的數據也要保存,否則無法從checkpoint中還原這個瞬間。checkpoint真正要保存的時刻是指的flink processing time或者event time概念下的瞬間。很顯然,圖中的這個瞬間至少Source和Task是不在一個“時刻”的,因爲Source1的“時間”顯然晚於Task1的“時間”。

flink-checkpoint-01

Easy Understand

在理想情況下,checkpoint主要是完成一下這幾個動作:

  1. 暫停新數據的輸入
  2. 等待流中on-the-fly的數據被處理乾淨,此時得到flink graph的一個snapshot
  3. 將所有Task中的State拷貝到State Backend中,如HDFS。此動作由各個Task Manager完成
  4. 各個Task Manager將Task State的位置上報給Job Manager,完成checkpoint
  5. 恢復數據的輸入

如上所述,這裏才需要“暫停輸入+排幹on-the-fly數據”的操作,這樣才能拿到同一時刻下所有subtask的state。這又必然引入了STW的副作用。

Chandy-Lamport algorithm

於是有了Chandy-Lamport算法。他解決的問題,就是在不停止流處理的前提下拿到每個subtask在某一瞬間的snapshot,從而完成checkpoint。

  1. 在checkpoint觸發時刻,Job Manager會往所有Source的流中放入一個barrier(圖中三角形)。barrier包含當前checkpoint的ID
flink-checkpoint-02
  1. 當barrier經過一個subtask時,即表示當前這個subtask處於checkpoint觸發的“時刻”,他就會立即將barrier法往下游,並執行checkpoint方法將當前的state存入backend storage。圖中Source1和Source2就是完成了checkpoint動作。
flink-checkpoint-03
  1. 如果一個subtask有多個上游節點,這個subtask就需要等待所有上游發來的barrier都接收到,才能表示這個subtask到達了checkpoint觸發“時刻”。但所有節點的barrier不一定一起到達,這時候就會面臨“是否要對齊barrier”的問題(Barrier Alignment)。如圖中的Task1.1,他有2個上游節點,Source1和Source2。假設Source1的barrier先到,這時候Task1.1就有2個選擇:
    • 是馬上把這個barrier發往下游並等待Source2的barrier來了再做checkpoint
    • 還是把Source1這邊後續的event全都cache起來,等Source2的barrier來了,在做checkpoint,完了再繼續處理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“時刻”之後數據的狀態。但是對於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需要結合外部系統一起完成,這裏就不做討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章