零基礎學 Flink:Window & Watermark
在上一篇文章中,我們學習了flink的時間。 本文我們來一起研究下 window 和 watermark 。
Window
首先,window是無界流資料處理的關鍵,flink將無界流拆分成無數個window。並對其生命週期進行了定義:
In a nutshell, a window is created as soon as the first element that should belong to this window arrives, and the window is completely removed when the time (event or processing time) passes its end timestamp plus the user-specified allowed lateness
(see Allowed Lateness).
一個視窗會在屬於其的第一個元素進入的時被建立,當時間(事件時間或處理時間)超過其結束時間加上使用者允許的延遲時間後,該視窗被移除。
在flink官方將視窗分為滾動視窗(Tumbling Windows),滑動視窗(Sliding Windows),會話視窗(Session Windows),全域性視窗(Global Windows)。全域性視窗是一種特殊型別的視窗,不在今天咱們討論的範圍之內。
滾動視窗:滾動視窗分派器(assigner)會將資料元素分派給指定大小的視窗,滾動視窗尺寸固定,相互不會重疊。
滑動視窗:滑動視窗分派器將元素分派給固定長度的視窗。與滾動視窗分派器類似,視窗大小可由引數配置。還有另外一個引數控制滑動視窗的啟動頻率。因此,如果滑動視窗小於視窗大小,則滑動視窗可以重疊。在這種情況下,元素被分配到多個視窗。如果滑動視窗大於視窗大小,則視窗變成抽樣資料。
會話視窗:會話視窗分派器按活動會話對元素進行分組。與滾動視窗和滑動視窗相比,會話視窗不重疊,也沒有固定的開始和結束時間。當會話視窗在一段時間內不接收元素時(即,當出現不活動間隙時),它將關閉。
下圖,是我認為描述視窗最為清晰的一張了。
這張圖,需要從下往上看,最下面定義了原始資料的輸入流,即在第一分鐘進入2個數據96,第二分鐘進入848,以此類推。
倒數第二行,是一個固定時間的滾動視窗,其視窗大小為1分鐘。
倒數第三行,是一個滑動視窗,需要資料滑動視窗的視窗尺寸和滑動尺寸。
倒數第四行,是一個固定元素個數的滾動視窗,即每3個元素一滾。
最上面則是一個會話視窗,只要會話有間隙,就會重新構建視窗。
Watermark
通過上面一章的內容,我們可以看出每個視窗都會有 開始時間 和 結束時間( 一般window的時間視窗為左閉右開的區間範圍 ) ,在這段時間內,我們是否能拿到所有需要處理的資料,我們就需要watermark來配合了,在之前的文章裡,由於理解的原因,我推薦過大家使用翻譯水印,但是現在,我覺得還是叫水位線更合適一些。
這裡引用阿里雲棲的一段描述
Watermark是Apache Flink為了處理EventTime 視窗計算提出的一種機制,本質上也是一種時間戳,由Apache Flink Source或者自定義的Watermark生成器按照需求Punctuated或者Periodic兩種方式生成的一種系統Event,與普通資料流Event一樣流轉到對應的下游運算元,接收到Watermark Event的運算元以此不斷調整自己管理的EventTime clock。 Apache Flink 框架保證Watermark單調遞增,運算元接收到一個Watermark時候,框架知道不會再有任何小於該Watermark的時間戳的資料元素到來了,所以Watermark可以看做是告訴Apache Flink框架資料流已經處理到什麼位置(時間維度)的方式。 Watermark的產生和Apache Flink內部處理邏輯如下圖所示:
從上文中,我們可以得出兩個觸發watermark的必要條件
-
watermark時間 >= 視窗的結束時間
-
在視窗的時間範圍(左閉右開)內有資料
那麼,flink是如何避免資料亂流的呢?我們來看下面一張圖
這是一個典型的單通道的場景,首先我們有一個時間事件佇列{2,3,1,7,3,5,9,6,12} ,兩個wartermark(W4,W9)事件通過時間戳被指派給了視窗(T1-T4)。
資料流入2,3,1進入視窗,7不屬於當前事件視窗,所以指派給了新視窗(T4-T8)。
資料繼續流入,此時水位線到達W4,觸發視窗(T1-T4)計算。
資料繼續流入,9被指派給了新視窗(T9-T12)( *筆者注,這個圖的事件視窗不對,個人認為是T8-T12 )
關於多通道的場景,我也推薦雲棲的這張圖,比官方文件裡的要好理解一些,配合上面的案例,相信大家也能讀懂。
現在我們已經瞭解watermark是如何工作的,那麼它是如何產生的呢?在flink裡主要有兩種方式產生watermark,即週期性的(Periodic)和標記性的(Punctuated)
Punctuated:資料流中每一個遞增的EventTime都會產生一個Watermark。
在實際的生產中Punctuated方式在TPS很高的場景下會產生大量的Watermark在一定程度上對下游運算元造成壓力,所以只有在實時性要求非常高的場景才會選擇Punctuated的方式進行Watermark的生成。
Periodic:週期性的(一定時間間隔或者達到一定的記錄條數)產生一個Watermark。在實際的生產中Periodic的方式必須結合時間和積累條數兩個維度繼續週期性產生Watermark,否則在極端情況下會有很大的延時。
所以Watermark的生成方式需要根據業務場景的不同進行不同的選擇。
好了,關於 window 和 watermark 就暫時說到這了,僅代表個人理解,如有問題,望指正,歡迎轉載,著名出處。
後續,會整理一些DEMO與大家分享。
最後,強烈推薦大家讀一讀雲棲的那篇文章,本文也是節選了部分。
參考資料:
https://yq.aliyun.com/articles/666056
https://ci.apache.org/projects/flink/flink-docs-master/dev/stream/operators/windows.html
https://ci.apache.org/projects/flink/flink-docs-release-1.7/dev/event_timestamps_watermarks.html
https://blog.csdn.net/u4110122855/article/details/81360381