前言
目前有許多數(shù)據(jù)分析的場景從批處理到流處理的演變烹植, 雖然可以將批處理作為流處理的特殊情況來處理泞坦,但是分析無窮集的流數(shù)據(jù)通常需要思維方式的轉(zhuǎn)變并且具有其自己的術(shù)語(例如沪斟,“windowing(窗口化)”、“at-least-once(至少一次)”暇矫、“exactly-once(只有一次)” )主之。
對于剛剛接觸流處理的人來說,這種轉(zhuǎn)變和新術(shù)語可能會非忱罡混亂槽奕。 Apache Flink 是一個為生產(chǎn)環(huán)境而生的流處理器,具有易于使用的 API房轿,可以用于定義高級流分析程序粤攒。
Flink 的 API 在數(shù)據(jù)流上具有非常靈活的窗口定義,使其在其他開源流處理框架中脫穎而出囱持。
在這篇文章中夯接,我們將討論用于流處理的窗口的概念,介紹 Flink 的內(nèi)置窗口纷妆,并解釋它對自定義窗口語義的支持盔几。
什么是 Windows?
下面我們結(jié)合一個現(xiàn)實的例子來說明掩幢。
就拿交通傳感器的示例:統(tǒng)計經(jīng)過某紅綠燈的汽車數(shù)量之和逊拍?
假設(shè)在一個紅綠燈處,我們每隔 15 秒統(tǒng)計一次通過此紅綠燈的汽車數(shù)量际邻,如下圖:
可以把汽車的經(jīng)過看成一個流芯丧,無窮的流,不斷有汽車經(jīng)過此紅綠燈世曾,因此無法統(tǒng)計總共的汽車數(shù)量缨恒。但是,我們可以換一種思路轮听,每隔 15 秒骗露,我們都將與上一次的結(jié)果進(jìn)行 sum 操作(滑動聚合),如下:
這個結(jié)果似乎還是無法回答我們的問題蕊程,根本原因在于流是無界的椒袍,我們不能限制流,但可以在有一個有界的范圍內(nèi)處理無界的流數(shù)據(jù)藻茂。
因此驹暑,我們需要換一個問題的提法:每分鐘經(jīng)過某紅綠燈的汽車數(shù)量之和玫恳?
這個問題,就相當(dāng)于一個定義了一個 Window(窗口)优俘,window 的界限是1分鐘京办,且每分鐘內(nèi)的數(shù)據(jù)互不干擾,因此也可以稱為翻滾(不重合)窗口帆焕,如下圖:
第一分鐘的數(shù)量為8惭婿,第二分鐘是22,第三分鐘是27叶雹。财饥。。這樣折晦,1個小時內(nèi)會有60個window钥星。
再考慮一種情況,每30秒統(tǒng)計一次過去1分鐘的汽車數(shù)量之和:
此時满着,window 出現(xiàn)了重合谦炒。這樣,1個小時內(nèi)會有120個 window风喇。
擴展一下宁改,我們可以在某個地區(qū),收集每一個紅綠燈處汽車經(jīng)過的數(shù)量魂莫,然后每個紅綠燈處都做一次基于1分鐘的window統(tǒng)計还蹲,即并行處理:
它有什么作用?
通常來講豁鲤,Window 就是用來對一個無限的流設(shè)置一個有限的集合秽誊,在有界的數(shù)據(jù)集上進(jìn)行操作的一種機制鲸沮。window 又可以分為基于時間(Time-based)的 window 以及基于數(shù)量(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 操作將會在后續(xù)的文章中講到。
Time Windows
正如命名那樣归敬,Time Windows 根據(jù)時間來聚合流數(shù)據(jù)酷含。例如:一分鐘的 tumbling time window 收集一分鐘的元素鄙早,并在一分鐘過后對窗口中的所有元素應(yīng)用于一個函數(shù)。
在 Flink 中定義 tumbling time windows(翻滾時間窗口) 和 sliding time windows(滑動時間窗口) 非常簡單:
tumbling time windows(翻滾時間窗口)
輸入一個時間參數(shù)
data.keyBy(1)
.timeWindow(Time.minutes(1)) //tumbling time window 每分鐘統(tǒng)計一次數(shù)量和
.sum(1);
sliding time windows(滑動時間窗口)
輸入兩個時間參數(shù)
data.keyBy(1)
.timeWindow(Time.minutes(1), Time.seconds(30)) //sliding time window 每隔 30s 統(tǒng)計過去一分鐘的數(shù)量和
.sum(1);
有一點我們還沒有討論椅亚,即“收集一分鐘的元素”的確切含義限番,它可以歸結(jié)為一個問題,“流處理器如何解釋時間?”
Apache Flink 具有三個不同的時間概念呀舔,即 processing time, event time 和 ingestion time弥虐。
這里可以參考我下一篇文章:
《從0到1學(xué)習(xí)Flink》—— 介紹Flink中的Event Time、Processing Time和Ingestion Time
Count Windows
Apache Flink 還提供計數(shù)窗口功能媚赖。如果計數(shù)窗口設(shè)置的為 100 霜瘪,那么將會在窗口中收集 100 個事件,并在添加第 100 個元素時計算窗口的值惧磺。
在 Flink 的 DataStream API 中粥庄,tumbling count window 和 sliding count window 的定義如下:
tumbling count window
輸入一個時間參數(shù)
data.keyBy(1)
.countWindow(100) //統(tǒng)計每 100 個元素的數(shù)量之和
.sum(1);
sliding count window
輸入兩個時間參數(shù)
data.keyBy(1)
.countWindow(100, 10) //每 10 個元素統(tǒng)計過去 100 個元素的數(shù)量之和
.sum(1);
解剖 Flink 的窗口機制
Flink 的內(nèi)置 time window 和 count window 已經(jīng)覆蓋了大多數(shù)應(yīng)用場景,但是有時候也需要定制窗口邏輯豺妓,此時 Flink 的內(nèi)置的 window 無法解決這些問題惜互。為了還支持自定義 window 實現(xiàn)不同的邏輯,DataStream API 為其窗口機制提供了接口琳拭。
下圖描述了 Flink 的窗口機制训堆,并介紹了所涉及的組件:
到達(dá)窗口操作符的元素被傳遞給 WindowAssigner。WindowAssigner 將元素分配給一個或多個窗口白嘁,可能會創(chuàng)建新的窗口坑鱼。
窗口本身只是元素列表的標(biāo)識符,它可能提供一些可選的元信息絮缅,例如 TimeWindow 中的開始和結(jié)束時間鲁沥。注意,元素可以被添加到多個窗口耕魄,這也意味著一個元素可以同時在多個窗口存在画恰。
每個窗口都擁有一個 Trigger(觸發(fā)器),該 Trigger(觸發(fā)器) 決定何時計算和清除窗口吸奴。當(dāng)先前注冊的計時器超時時允扇,將為插入窗口的每個元素調(diào)用觸發(fā)器。在每個事件上则奥,觸發(fā)器都可以決定觸發(fā)(即考润、清除(刪除窗口并丟棄其內(nèi)容),或者啟動并清除窗口读处。一個窗口可以被求值多次糊治,并且在被清除之前一直存在。注意罚舱,在清除窗口之前井辜,窗口將一直消耗內(nèi)存揖赴。
當(dāng) Trigger(觸發(fā)器) 觸發(fā)時,可以將窗口元素列表提供給可選的 Evictor抑胎,Evictor 可以遍歷窗口元素列表燥滑,并可以決定從列表的開頭刪除首先進(jìn)入窗口的一些元素。然后其余的元素被賦給一個計算函數(shù)阿逃,如果沒有定義 Evictor铭拧,觸發(fā)器直接將所有窗口元素交給計算函數(shù)。
計算函數(shù)接收 Evictor 過濾后的窗口元素恃锉,并計算窗口的一個或多個元素的結(jié)果搀菩。 DataStream API 接受不同類型的計算函數(shù),包括預(yù)定義的聚合函數(shù)破托,如 sum()肪跋,min(),max()土砂,以及 ReduceFunction州既,F(xiàn)oldFunction 或 WindowFunction。
這些是構(gòu)成 Flink 窗口機制的組件萝映。 接下來我們逐步演示如何使用 DataStream API 實現(xiàn)自定義窗口邏輯吴叶。 我們從 DataStream [IN] 類型的流開始,并使用 key 選擇器函數(shù)對其分組序臂,該函數(shù)將 key 相同類型的數(shù)據(jù)分組在一塊蚌卤。
SingleOutputStreamOperator<xxx> data = env.addSource(...);
data.keyBy()
如何自定義 Window?
1奥秆、Window Assigner
負(fù)責(zé)將元素分配到不同的 window逊彭。
Window API 提供了自定義的 WindowAssigner 接口,我們可以實現(xiàn) WindowAssigner 的
public abstract Collection<W> assignWindows(T element, long timestamp)
方法构订。同時侮叮,對于基于 Count 的 window 而言,默認(rèn)采用了 GlobalWindow 的 window assigner鲫咽,例如:
keyBy.window(GlobalWindows.create())
2签赃、Trigger
Trigger 即觸發(fā)器,定義何時或什么情況下移除 window
我們可以指定觸發(fā)器來覆蓋 WindowAssigner 提供的默認(rèn)觸發(fā)器分尸。 請注意,指定的觸發(fā)器不會添加其他觸發(fā)條件歹嘹,但會替換當(dāng)前觸發(fā)器箩绍。
3、Evictor(可選)
驅(qū)逐者尺上,即保留上一 window 留下的某些元素
4材蛛、通過 apply WindowFunction 來返回 DataStream 類型數(shù)據(jù)圆到。
利用 Flink 的內(nèi)部窗口機制和 DataStream API 可以實現(xiàn)自定義的窗口邏輯,例如 session window卑吭。
結(jié)論
對于現(xiàn)代流處理器來說芽淡,支持連續(xù)數(shù)據(jù)流上的各種類型的窗口是必不可少的。 Apache Flink 是一個具有強大功能集的流處理器豆赏,包括一個非常靈活的機制挣菲,可以在連續(xù)數(shù)據(jù)流上構(gòu)建窗口。 Flink 為常見場景提供內(nèi)置的窗口運算符掷邦,以及允許用戶自定義窗口邏輯白胀。
參考
1、https://flink.apache.org/news/2015/12/04/Introducing-windows.html
2抚岗、https://blog.csdn.net/lmalds/article/details/51604501
關(guān)注我
轉(zhuǎn)載請務(wù)必注明原創(chuàng)地址為:http://www.54tianzhisheng.cn/2018/12/08/Flink-Stream-Windows/
微信公眾號:zhisheng
另外我自己整理了些 Flink 的學(xué)習(xí)資料或杠,目前已經(jīng)全部放到微信公眾號了。你可以加我的微信:zhisheng_tian宣蔚,然后回復(fù)關(guān)鍵字:Flink 即可無條件獲取到向抢。
Github 代碼倉庫
https://github.com/zhisheng17/flink-learning/
以后這個項目的所有代碼都將放在這個倉庫里,包含了自己學(xué)習(xí) flink 的一些 demo 和博客
相關(guān)文章
1胚委、《從0到1學(xué)習(xí)Flink》—— Apache Flink 介紹
2笋额、《從0到1學(xué)習(xí)Flink》—— Mac 上搭建 Flink 1.6.0 環(huán)境并構(gòu)建運行簡單程序入門
3、《從0到1學(xué)習(xí)Flink》—— Flink 配置文件詳解
4篷扩、《從0到1學(xué)習(xí)Flink》—— Data Source 介紹
5兄猩、《從0到1學(xué)習(xí)Flink》—— 如何自定義 Data Source ?
6鉴未、《從0到1學(xué)習(xí)Flink》—— Data Sink 介紹
7枢冤、《從0到1學(xué)習(xí)Flink》—— 如何自定義 Data Sink ?
8铜秆、《從0到1學(xué)習(xí)Flink》—— Flink Data transformation(轉(zhuǎn)換)
9淹真、《從0到1學(xué)習(xí)Flink》—— 介紹Flink中的Stream Windows
10、《從0到1學(xué)習(xí)Flink》—— Flink 中的幾種 Time 詳解
11连茧、《從0到1學(xué)習(xí)Flink》—— Flink 寫入數(shù)據(jù)到 ElasticSearch