DataStream 編程模型
- DataSource模塊負責數據接入
- 內置數據源:文件數據源readTextFile/readFile(InputFormat),Socket端口socketTextStream,集合數據源 fromElements
- 第三方數據源:
- 僅支持讀取:Netty
- 僅支持輸出:ElasticSearch,HDFS
- 支持讀取和輸出:Kafaka,RabbitMQ
- 用戶自定義數據源連接器
- Transformation模塊負責數據集的各種轉換操作
- 單SingleDataStream:對單個DataStream的處理邏輯
- Map[DataStream->DataStream],map函數可以直接傳入匿名計算表達式,也可以實現匿名的MapFunction類,覆蓋其中的map方法。
- FlatMap[DataStream->DataStream]
- Filter[DataStream->DataStream],符合表達式的留下來,不符合的過濾掉。
- KeyBy[DataStream->KeyedStream],執行Partition操作,將相同的Key值放入相同的分區。
- Reduce[KeyedStream->DataStream],可直接傳入匿名的reduce函數,也可實現匿名的ReduceFunction類。
- Aggregations[KeyedStream->DataStream], 根據指定的字段進行聚合操作,滾動計算參數聚合結果,即一個reduce操作個例。例如 sum,min,minBy(返回最小值對應的元素),max,maxBy
- MultiDataStream:對多個DataStream的處理邏輯
- Union[DataStream->DataStream],需要保證兩個數據集的格式一致。
- Connect,CoMap,CoFlatMap[DataStream->DataStream]
- Split[DataStream->SplitStream]
- Select[SplitStream->DataStream]
- Iterate[DataStream->IterativeStream->DataStream]
- 物理分區:並行度和數據分區的調整轉換
- shuffle:隨機重新分區,分區相對平衡,但是容易失去原有的數據分區結構。
- rebalance:通過循環的方式對數據集中的數據進行重分區,儘可能地保證每個分區的數據平衡。
- rescale:循環處理,並僅會對上下游的算子數據進行重新平衡。
- broadcast:將數據集複製到下游的算子task中,防止網絡拉取。
- 自定義分區 extends Partitioner
- 單SingleDataStream:對單個DataStream的處理邏輯
- DataSink模塊負責寫出到外部存儲
- 基本數據輸出:writeAsCsv,writeAsText,writeToSocket
- 第三方數據輸出:FlinkKafkaProducer
時間概念與Watermark
時間的概念
-
事件生成時間 Event Time,時間實際發生時間
-
事件接入時間 Ingestion Time,傳送至DataSource時的機器時間
-
事件處理時間 Processing Time,到達某個算子操作時獲取的機器時間
在Flink中默認情況下使用的是Process Time,因此要使用其他兩種時間時,需要顯示指定。
//指定時間類型
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
EventTime和Watermark
Watermark是水位線的意思,一個基於事件時間的Window是水槽,Watermark用於判斷該水槽中的水是否全部流入了,是一個表達數據完整性的統計量。
Watermark=EventTime-最大延遲到達時間
當窗口結束時間大於Watermark,並且該窗口中有事件數據時,就會觸發窗口計算。
Timestamps Assigning與生成Watermarks
使用EventTime需要說明如何從事件數據中提取Timestamp,該過程叫做Timestams Assigning。
得到EventTime之後,需要制定Watermarks的生成策略。
兩種方式:
-
在DataStream Source 算子接口的Source Function 中定義。
-
通過Flink自帶的Timestamp Assigner 指定Timestamp 和生成Watermark
-
根據時間間隔週期性生成Watermark,AssignerWithPeriodicWatermarks
-
升序模式,適用於順序生成事件:assignAscendingTimestamps
-
固定時間延遲間隔
-
assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[AdsStateRealEntity](Time.minutes(1)) // 指定時間間隔爲1分鐘 { // 指定事件時間抽取方式 override def extractTimestamp(element: AdsStateRealEntity): Long = getUnixTime(element.getStatusStartTime) })
- 根據特定元素的數據滿足某個特定條件生成Watermark,AssignerWithPunctuatedWatermarks
-
-
自定義Timestamp Assinger 和 WartermarkGenerator。
-
Periodic Watermarks 自定義生成
-
Punctuated Watermarks 自定義生成
-
窗口計算
WindowsAssigner :指定窗口的類型,定義如何將數據流分配到一個或者多個窗口。
Windows Trigger:指定窗口觸發時機,定義窗口滿足什麼樣的條件觸發計算。
Evictor:用於數據剔除。
Lateness:標記是否處理遲到數據,當遲到數據到達窗口中是否觸發計算。
OutPut Tag:標記輸出標籤,然後通過getSideOutput將窗口中的數據根據標籤輸出。
Windows Function:定義窗口上數據處理的邏輯,例如對數據進行sum操作。
stream.keyBy( ... ) // window函數窗口操作必須是keyedStream,否則應該調用windowAll方法
.window( ... ) // 指定窗口分配器類型
[.trigger( ... )]// 指定觸發器類型(可選)
[.evictor( ... )]// 指定evictor(可選)
[.allowedLateness( ... )] // 指定是否延遲處理數據(可選)
[.sideOutputLateData( ... )] // 指定Output Tag (可選)
.reduce/aggregate/fold/apply() // 指定窗口計算函數
[.getSideOutput( ... )] // 根據Tag輸出數據(可選)
Windows Assigner
基於時間的窗口
TimeWindow 類來獲取窗口的起始時間和終止時間,以及該窗口允許進入的最新時間戳信息等元數據。
(1)滾動窗口:根據固定時間或者大小進行切分,且窗口和窗口之間的元素互不重疊。
TumblingEventTimeWindows 和 TumblingProcessTimeWindows 或者 timeWindow方法。
(2)滑動窗口:在滾動窗口的基礎之上,增加了窗口的滑動時間,並且允許數據重疊。窗口的大小,和滑動時間兩個參數確定了滑動的策略。當Slide time 小於 Windows size 是便會發生重疊。而當Slide time 大於 Windows 四則時則會發生不連續。
(3)會話窗口:會話窗口(Session Windows)主要是將某段時間內活躍度較高的數據聚合成一個窗口進行計算,窗口的觸發條件是Session Gap,是指在規定的時間內如果沒有數據活躍接入,則認爲窗口結束,然後觸發窗口計算。可以通過實現SessionWindowTimeGapExtractor接口,複寫extract方法動態定義session gap。
(4)全局窗口:全局窗口將所有相同的Key的數據分配到單個窗口中計算結果,窗口沒有起始時間和結束時間,窗口需要藉助Trigger來觸發計算,如果不對Global Windows 指定Trigger,窗口是不會觸發計算的
基於數量的窗口
countWindows()來定義基於數量的窗口。
Windows Function
- 增量聚合函數
- ReduceFunction
- AggregateFunction
- FoldFunction
- 全量窗口函數
- ProcessWindowFunction
Trigger 窗口觸發器
EventTimeTrigger:通過對比Wartermark 和窗口的EndTime 確定是否觸發窗口,如果Wartermark的時間大於Windows EndTime 則觸發計算,否則窗口繼續等待。
ProcessTimeTrigger:和EventTimeTrigger類似,只是使用ProcessTime確定。
ContinuousEventTimeTrigger:根據時間間隔週期性觸發窗口或者Window的結束時間小於當前EventTime觸發窗口計算。
ContinuousProcessingTimeTrigger:同上
CountTrigger:根據接入數據量是否超過設定的閾值確定是否觸發窗口計算。
DeltaTrigger:根據接入數據計算出來的Delta指標是否超過指定的Threshold來判斷是否觸發窗口計算。
PurgingTrigger:可將將任意觸發器作爲參數轉換爲Purge類型觸發器,計算完成後數據將被清理。
另外,用戶可以自定義Trigger。
Evictors 數據剔除器
數據剔除器的主要作用是對進入WindowFunction前後的數據進行剔除處理。
- CountEvictor:保持在窗口中具有固定數量的記錄,將超過指定大小的數據在窗口計算前剔除。
- DeltaEvictor:通過定義DeltaFunction 和 指定 threshold,並計算Windows中元素與最新元素之間的Delta大小,如果超過threshold則將當前數據元素剔除。
- TimeEvictor:通過指定時間間隔,將當前窗口中最新元素的時間減去Interval,然後將小於該結果的數據全部剔除,其本質是將具有最新時間的數據選擇出來,刪除過時數據。
- 用戶可自定義Evictor
延遲數據處理
基於Event-Time的窗口處理流式數據,在延遲非常高的情況下,依然會有部分數據未來得及進入應該進的窗口,Flink默認情況下是將這些數據丟棄,而Allowed Lateness機制對遲到的數據進行額外的處理。
對於指定了allowedLateness的窗口,計算過程中的Window的Endtime會加上該時間,作爲窗口最後被釋放的結束時間(P),如果EventTime超過了P則丟棄數據,如果EventTime未超過P,但是Wartermark已經超過Endtime則觸發計算,對於未參與計算的數據,可以通過sideOutputLateData方法打上late-data標籤,然後通過getSideOutput方法獲取該標籤的數據,進行額外處理。
窗口計算
獨立窗口計算:針對同一個DataStream進行不同的窗口處理,窗口之間相對獨立,輸出結果在不同的DataStream中,這時在Flink Runtime 執行環境中,將分爲兩個Window Operator 在不同的Task中執行,相互之間的元數據無法共享。
連續窗口計算:連續窗口計算表示上游窗口計算的結果是下游窗口計算的輸入,窗口算子和算子之間是上下游關聯關係,窗口之間的元數據信息能夠共享。例如求每個key的最小值中最大的n個key。
Windows 多流合併 Join操作
在Windows Join 過程中所有的Join操作都是Inner-join類型,兩個關聯的窗口必須是同類型的。
滾動窗口關聯(Tumbling Window join)
滑動窗口關聯(Sliding Window join)
會話窗口關聯(Session Window join)
間隔窗口關聯(Interval Join)
作業鏈和資源組
在Flink作業中,用戶可以指定相應的鏈條,將相關性非常強的轉換操作綁定在一起,這樣能夠讓轉換過程上下游的Task在同一個Pipeline中執行。