《從0到1學習Flink》—— 介紹Flink中的Stream Windows
前言
目前有許多數據分析的場景從批處理到流處理的演變, 雖然可以將批處理作為流處理的特殊情況來處理,但是分析無窮集的流數據通常需要思維方式的轉變並且具有其自己的術語(例如,“windowing(窗口化)”、“at-least-once(至少一次)”、“exactly-once(只有一次)” )。
對於剛剛接觸流處理的人來說,這種轉變和新術語可能會非常混亂。 Apache Flink 是一個為生產環境而生的流處理器,具有易於使用的 API,可以用於定義高級流分析程序。
Flink 的 API 在數據流上具有非常靈活的窗口定義,使其在其他開源流處理框架中脫穎而出。
在這篇文章中,我們將討論用於流處理的窗口的概念,介紹 Flink 的內置窗口,並解釋它對自定義窗口語義的支持。
什麽是 Windows?
下面我們結合一個現實的例子來說明。
就拿交通傳感器的示例:統計經過某紅綠燈的汽車數量之和?
假設在一個紅綠燈處,我們每隔 15 秒統計一次通過此紅綠燈的汽車數量,如下圖:
可以把汽車的經過看成一個流,無窮的流,不斷有汽車經過此紅綠燈,因此無法統計總共的汽車數量。但是,我們可以換一種思路,每隔 15 秒,我們都將與上一次的結果進行 sum 操作(滑動聚合),如下:
這個結果似乎還是無法回答我們的問題,根本原因在於流是無界的,我們不能限制流,但可以在有一個有界的範圍內處理無界的流數據。
因此,我們需要換一個問題的提法:每分鐘經過某紅綠燈的汽車數量之和?
這個問題,就相當於一個定義了一個 Window(窗口),window 的界限是1分鐘,且每分鐘內的數據互不幹擾,因此也可以稱為翻滾(不重合)窗口,如下圖:
第一分鐘的數量為8,第二分鐘是22,第三分鐘是27。。。這樣,1個小時內會有60個window。
再考慮一種情況,每30秒統計一次過去1分鐘的汽車數量之和:
此時,window 出現了重合。這樣,1個小時內會有120個 window。
擴展一下,我們可以在某個地區,收集每一個紅綠燈處汽車經過的數量,然後每個紅綠燈處都做一次基於1分鐘的window統計,即並行處理:
它有什麽作用?
通常來講,Window 就是用來對一個無限的流設置一個有限的集合,在有界的數據集上進行操作的一種機制。window 又可以分為基於時間(Time-based)的 window 以及基於數量(Count-based)的 window。
Flink 自帶的 window
Flink DataStream API 提供了 Time 和 Count 的 window,同時增加了基於 Session 的 window。同時,由於某些特殊的需要,DataStream API 也提供了定制化的 window 操作,供用戶自定義 window。
下面,主要介紹 Time-Based window 以及 Count-Based window,以及自定義的 window 操作,Session-Based Window 操作將會在後續的文章中講到。
Time Windows
正如命名那樣,Time Windows 根據時間來聚合流數據。例如:一分鐘的 tumbling time window 收集一分鐘的元素,並在一分鐘過後對窗口中的所有元素應用於一個函數。
在 Flink 中定義 tumbling time windows(翻滾時間窗口) 和 sliding time windows(滑動時間窗口) 非常簡單:
tumbling time windows(翻滾時間窗口)
輸入一個時間參數
data.keyBy(1)
.timeWindow(Time.minutes(1)) //tumbling time window 每分鐘統計一次數量和
.sum(1);
sliding time windows(滑動時間窗口)
輸入兩個時間參數
data.keyBy(1)
.timeWindow(Time.minutes(1), Time.seconds(30)) //sliding time window 每隔 30s 統計過去一分鐘的數量和
.sum(1);
有一點我們還沒有討論,即“收集一分鐘的元素”的確切含義,它可以歸結為一個問題,“流處理器如何解釋時間?”
Apache Flink 具有三個不同的時間概念,即 processing time, event time 和 ingestion time。
這裏可以參考我下一篇文章:
《從0到1學習Flink》—— 介紹Flink中的Event Time、Processing Time和Ingestion Time
Count Windows
Apache Flink 還提供計數窗口功能。如果計數窗口設置的為 100 ,那麽將會在窗口中收集 100 個事件,並在添加第 100 個元素時計算窗口的值。
在 Flink 的 DataStream API 中,tumbling count window 和 sliding count window 的定義如下:
tumbling count window
輸入一個時間參數
data.keyBy(1)
.countWindow(100) //統計每 100 個元素的數量之和
.sum(1);
sliding count window
輸入兩個時間參數
data.keyBy(1)
.countWindow(100, 10) //每 10 個元素統計過去 100 個元素的數量之和
.sum(1);
解剖 Flink 的窗口機制
Flink 的內置 time window 和 count window 已經覆蓋了大多數應用場景,但是有時候也需要定制窗口邏輯,此時 Flink 的內置的 window 無法解決這些問題。為了還支持自定義 window 實現不同的邏輯,DataStream API 為其窗口機制提供了接口。
下圖描述了 Flink 的窗口機制,並介紹了所涉及的組件:
到達窗口操作符的元素被傳遞給 WindowAssigner。WindowAssigner 將元素分配給一個或多個窗口,可能會創建新的窗口。
窗口本身只是元素列表的標識符,它可能提供一些可選的元信息,例如 TimeWindow 中的開始和結束時間。註意,元素可以被添加到多個窗口,這也意味著一個元素可以同時在多個窗口存在。
每個窗口都擁有一個 Trigger(觸發器),該 Trigger(觸發器) 決定何時計算和清除窗口。當先前註冊的計時器超時時,將為插入窗口的每個元素調用觸發器。在每個事件上,觸發器都可以決定觸發(即、清除(刪除窗口並丟棄其內容),或者啟動並清除窗口。一個窗口可以被求值多次,並且在被清除之前一直存在。註意,在清除窗口之前,窗口將一直消耗內存。
當 Trigger(觸發器) 觸發時,可以將窗口元素列表提供給可選的 Evictor,Evictor 可以遍歷窗口元素列表,並可以決定從列表的開頭刪除首先進入窗口的一些元素。然後其余的元素被賦給一個計算函數,如果沒有定義 Evictor,觸發器直接將所有窗口元素交給計算函數。
計算函數接收 Evictor 過濾後的窗口元素,並計算窗口的一個或多個元素的結果。 DataStream API 接受不同類型的計算函數,包括預定義的聚合函數,如 sum(),min(),max(),以及 ReduceFunction,FoldFunction 或 WindowFunction。
這些是構成 Flink 窗口機制的組件。 接下來我們逐步演示如何使用 DataStream API 實現自定義窗口邏輯。 我們從 DataStream [IN] 類型的流開始,並使用 key 選擇器函數對其分組,該函數將 key 相同類型的數據分組在一塊。
SingleOutputStreamOperator<xxx> data = env.addSource(...);
data.keyBy()
如何自定義 Window?
1、Window Assigner
負責將元素分配到不同的 window。
Window API 提供了自定義的 WindowAssigner 接口,我們可以實現 WindowAssigner 的
public abstract Collection<W> assignWindows(T element, long timestamp)
方法。同時,對於基於 Count 的 window 而言,默認采用了 GlobalWindow 的 window assigner,例如:
keyBy.window(GlobalWindows.create())
2、Trigger
Trigger 即觸發器,定義何時或什麽情況下移除 window
我們可以指定觸發器來覆蓋 WindowAssigner 提供的默認觸發器。 請註意,指定的觸發器不會添加其他觸發條件,但會替換當前觸發器。
3、Evictor(可選)
驅逐者,即保留上一 window 留下的某些元素
4、通過 apply WindowFunction 來返回 DataStream 類型數據。
利用 Flink 的內部窗口機制和 DataStream API 可以實現自定義的窗口邏輯,例如 session window。
結論
對於現代流處理器來說,支持連續數據流上的各種類型的窗口是必不可少的。 Apache Flink 是一個具有強大功能集的流處理器,包括一個非常靈活的機制,可以在連續數據流上構建窗口。 Flink 為常見場景提供內置的窗口運算符,以及允許用戶自定義窗口邏輯。
參考
1、https://flink.apache.org/news/2015/12/04/Introducing-windows.html
2、https://blog.csdn.net/lmalds/article/details/51604501
關註我
轉載請務必註明原創地址為:http://www.54tianzhisheng.cn/2018/12/08/Flink-Stream-Windows/
微信公眾號:zhisheng
另外我自己整理了些 Flink 的學習資料,目前已經全部放到微信公眾號了。你可以加我的微信:zhisheng_tian,然後回復關鍵字:Flink 即可無條件獲取到。
Github 代碼倉庫
https://github.com/zhisheng17/flink-learning/
以後這個項目的所有代碼都將放在這個倉庫裏,包含了自己學習 flink 的一些 demo 和博客
相關文章
1、《從0到1學習Flink》—— Apache Flink 介紹
2、《從0到1學習Flink》—— Mac 上搭建 Flink 1.6.0 環境並構建運行簡單程序入門
3、《從0到1學習Flink》—— Flink 配置文件詳解
4、《從0到1學習Flink》—— Data Source 介紹
5、《從0到1學習Flink》—— 如何自定義 Data Source ?
6、《從0到1學習Flink》—— Data Sink 介紹
7、《從0到1學習Flink》—— 如何自定義 Data Sink ?
8、《從0到1學習Flink》—— Flink Data transformation(轉換)
9、《從0到1學習Flink》—— 介紹Flink中的Stream Windows
10、《從0到1學習Flink》—— Flink 中的幾種 Time 詳解
11、《從0到1學習Flink》—— Flink 寫入數據到 ElasticSearch
12、《從0到1學習Flink》—— Flink 項目如何運行?
13、《從0到1學習Flink》—— Flink 寫入數據到 Kafka
《從0到1學習Flink》—— 介紹Flink中的Stream Windows