巨量資料理論篇 No.2-聊聊Flink流計算中的Timestamp和Watermark

2020-10-25 16:00:40

第1章 時間語意

Flink裡定義了三種時間語意:Event Time、Ingestion Time、Processing Time。

在整個流計算過程中,他們分別代表事件發生的時間資料最早進入Flink的時間資料被Flink運算元處理時運算元原生的時間

Event Time:事件發生時間,現實世界中資料真實產生的時間。無論資料流在傳輸和計算過程中花了多少時間EventTime是不會變的,它在時間發生時就已經確定。

Ingestion Time:資料最早進入Flink的時間,也就是資料到達Source的時間,Ingest Time同樣不受內部運算元計算和資料傳輸效率所影響。

Processing Time:資料進入每個運算元時,運算元所在機器上的本地時間。Process Time只依賴當前運算元所在機器的系統時鐘。

 

第2章 Timestamp

EventTime模式下,Flink從Source流入的所有資料都會包含Timestamp,這裡的所指的Timestamp代表的是事件發生的時間。當然也可以是自定義的Timestamp。但是一定要保證時間戳的遞增性。

舉個例子,在業務上我們經常需要用到的視窗計算,計算某時間端內事件發生的次數:計算近兩週內各地區確診病例的數量,計算近一個小時各模組的存取量和使用者點選量,等等……,這些都需要EventTIme模式下利用Timestamp做視窗計算。

在Flink裡,Timestamp被定義為8位元組的long值。每個運算元拿到資料時,預設以毫秒精度的Unix時間戳解析這個long值,也就是自1970-01-01 00:00:00.000以來的毫秒數。當然自定義的運算元可以自己定義時間戳的解析方式。

但是基於時間的應用,由於每個計算單元的計算能力不同、網路傳輸的速率也不同,而且現今巨量資料系統都是分散式架構。因為這些種種原因,資料到達Source和每一個計算單元都會存在一定的不確定性,這就是時間亂序問題。接下來我們看看Flink如何解決這種資料的亂序問題:Watermark。

 

第3章 Watermark

Flink定義了Watermark,它是一種資料元素StreamElement,和普通資料一起在運算元之間傳輸。本質上是一個long型別的Timestamp,是一個全域性進度指標。

Watermark可以在Source位置發射,也可以在流傳輸的任何運算元上產生,並通過拓撲中的運運算元傳播。

在FLink流計算過程中,既然資料傳輸會有延遲,資料會產生亂序,那麼在我們該在什麼時候觸發視窗計算呢?換一個思路,可以這麼說:我們該如何知道要等多久才能確定視窗計算的資料都已經全部到達運算元了呢?

我們來看上面這張圖,Flink利用穿插在資料流當中的Watermark,Watermark讓運算元確信不會再有延遲事件到來,從而觸發運算元做視窗計算。那實際上在Watermark之後到底還會不會有該視窗的資料被遺漏呢?上面的示意圖就已經解答了這個問題:可能會有。如果Watermark定義的延遲越小,那麼存在遺漏可能性就越大;Watermark延遲定義的延遲越大,遺漏的可能性就越小,但是這也意味著,視窗觸發的延遲越久。

所以Watermark在通常情況下,是需要自己根據自己的業務,去實際的測試調整,達到一個均衡值。在有些情況下,使用者為了降低計算的延遲,又希望不直接捨棄那些被Watermark排除在外的資料,那麼可以將這些資料寫入紀錄檔或者利用這些資料去修正之前的結果。

最後多一句嘴:基於Processing Time的視窗計算不需要Watermark。