Flink 小貼士 (3): 輕鬆理解 Watermark
原文: ofollow,noindex">https://data-artisans.com/blog/watermarks-in-apache-flink-made-easy
作者:David Anderson
譯者:雲邪(Jark)
當人們第一次使用 Flink 時,經常會對 watermark 感到困惑。但其實 watermark 並不複雜。讓我們通過一個簡單的例子來說明為什麼我們需要 watermark,以及它的工作機制是什麼樣的。
在 Apache Flink 中使用 watermark 的 4 個觀察結果
在下文中的例子中,我們有一個帶有時間戳的事件流,但是由於某種原因它們並不是按順序到達的。圖中的數字代表事件發生的時間戳。第一個到達的事件發生在時間 4,然後它後面跟著的是發生在更早時間(時間 2)的事件,以此類推:
注意這是一個按照事件時間處理的例子,這意味著時間戳反映的是事件發生的時間,而不是處理事件的時間。事件時間(Event-Time)處理的強大之處在於,無論是在處理實時的資料還是重新處理歷史的資料,基於事件時間建立的流計算應用都能保證結果是一樣的。
注:可以訪問 Apache Flink 文件 ,瞭解更多有關時間的概念,如 event-time, processing-time, ingestion-time。
現在假設我們正在嘗試建立一個流計算排序運算元。也就是處理一個亂序到達的事件流,並按照事件時間的順序輸出事件。
觀察 #1:
資料流中的第一個元素的時間是 4,但是我們不能直接將它作為排序後資料流的第一個元素並輸出它。因為資料是亂序到達的,也許有一個更早發生的資料還沒有到達。事實上,我們能預見一些這個流的未來,也就是我們的排序運算元至少要等到 2 這條資料的到達再輸出結果。
有快取,就必然有延遲。
觀察 #2:
如果我們做錯了,我們可能會永遠等待下去。首先,我們的應用程式從看到時間 4 的資料,然後看到時間 2 的資料。是否會有一個比時間 2 更早的資料到達呢?也許會,也許不會。我們可以一直等下去,但可能永遠看不到 1 。
最終,我們必須勇敢地輸出 2 作為排序流的第一個結果。
觀察 #3:
我們需要的是某種策略,它定義了對於任何帶時間戳的事件流,何時停止等待更早資料的到來。
這正是 watermark 的作用,他們定義了何時不再等待更早的資料。
Flink 中的事件時間處理依賴於一種特殊的帶時間戳的元素,成為 watermark,它們會由資料來源或是 watermark 生成器插入資料流中。具有時間戳 t
的 watermark 可以被理解為斷言了所有時間戳 小於或等於 t
的事件都(在某種合理的概率上)已經到達了。
譯註:此處原文是“小於”,譯者認為應該是 “小於或等於”,因為 Flink 原始碼中採用的是 “小於或等於” 的機制。
何時我們的排序運算元應該停止等待,然後將事件 2 作為首個元素輸出?答案是當收到時間戳為 2(或更大)的 watermark 時。
觀察 #4:
我們可以設想不同的策略來生成 watermark。
我們知道每個事件都會延遲一段時間才到達,而這些延遲差異會比較大,所以有些事件會比其他事件延遲更多。一種簡單的方法是假設這些延遲不會超過某個最大值。Flink 把這種策略稱作 “有界無序生成策略”(bounded-out-of-orderness)。當然也有很多更復雜的方式去生成 watermark,但是對於大多數應用來說,固定延遲的方式已經足夠了。
如果想要構建一個類似排序的流應用,可以使用 Flink 的 ProcessFunction
。它提供了對事件時間計時器(基於 watermark 觸發回撥)的訪問,還提供了可以用來快取資料的託管狀態介面。
如果想要了解更多有關 Apache Flink 的 ProcessFunction
的實踐案例,可以訪問我的上一篇文章 《Flink 零基礎實戰教程:如何計算實時熱門商品》 瞭解如何使用 ProcessFunction
實現 TopN 功能。