Flink 原理与实现:Window 机制

参考网址:

https://blog.csdn.net/u4110122855/article/details/81360208

https://blog.csdn.net/u4110122855/article/details/81360381

1、流处理中Window的概念

流是无界的,我们不能限制流,但可以在有一个有界的范围内处理无界的流数据。

Flink 认为 Batch 是 Streaming 的一个特例,所以 Flink 底层引擎是一个流式引擎,在上面实现了流处理和批处理。而窗口(window)就是从 Streaming 到 Batch 的一个桥梁。

在流处理应用中,数据是连续不断的,因此我们不可能等到所有数据都到了才开始处理。当然我们可以每来一个消息就处理一次,但是有时我们需要做一些聚合类的处理,例如:在过去的1分钟内有多少用户点击了我们的网页。在这种情况下,我们必须定义一个窗口,用来收集最近一分钟内的数据,并对这个窗口内的数据进行计算。

通常来讲,Window就是用来对一个无限的流设置一个有限的集合,在有界的数据集上进行操作的一种机制。window又可以分为基于时间(Time-based)的window以及基于数量(Count-based)的window。

Flink DataStream API提供了Time和Count的window,同时增加了基于Session的window。同时,由于某些特殊的需要,DataStream API也提供了定制化的window操作,供用户自定义window。

(相关API在包org.apache.flink.streaming.api.windowing中)

1、Time-Based Window ,基于时间的窗口主要分为翻滚窗口和滑动窗口
1.1、Tumbling window(翻滚)

翻滚窗口又分基于处理时间的窗口TumblingProcessingTimeWindows和基于事件时间的窗口TumblingEventTimeWindows

API例子:

DataStream.keyBy(0).timeWindow(Time.minutes(1))

或者

DataStream.keyBy(0).window(TumblingProcessingTimeWindows.of(Time.seconds(5)))

此处的window要在keyed Stream上应用window操作,翻滚窗口只有一个时间参数

1.2、Sliding window(滑动)

滑动窗口跟翻滚窗口不同的是有两个时间参数

2、Count-Based Window 
2.1、Tumbling Window

API例子:

DataStream.keyBy(0).countWindow(100)

2.2、Sliding Window 

 

3、Advanced Window(自定义window) 
自定义的Window需要指定3个function。 
3.1、Window Assigner:负责将元素分配到不同的window。

3.2、Trigger 
Trigger即触发器,定义何时或什么情况下Fire一个window

3.3、Evictor(可选) 
驱逐者,即保留上一window留下的某些元素。

 

Flink 的窗口机制以及各组件之间是如何相互工作:

1、数据流源源不断地进入算子(window operator),每一个到达的元素都会被交给 WindowAssigner。WindowAssigner 会决定元素被放到哪个或哪些窗口(window),可能会创建新窗口。因为一个元素可以被放入多个窗口中(个人理解是滑动窗口,滚动窗口不会有此现象),所以同时存在多个窗口是可能的。注意,Window本身只是一个ID标识符,其内部可能存储了一些元数据,如TimeWindow中有开始和结束时间,但是并不会存储窗口中的元素。窗口中的元素实际存储在 Key/Value State 中,key为Window,value为元素集合(或聚合值)。为了保证窗口的容错性,该实现依赖了 Flink 的 State 机制。

2、每一个窗口都拥有一个属于自己的 Trigger,Trigger上会有定时器,用来决定一个窗口何时能够被计算或清除。每当有元素加入到该窗口,或者之前注册的定时器超时了,那么Trigger都会被调用。Trigger的返回结果可以是 continue(不做任何操作),fire(处理窗口数据),purge(移除窗口和窗口中的数据),或者 fire + purge。一个Trigger的调用结果只是fire的话,那么会计算窗口并保留窗口原样,也就是说窗口中的数据仍然保留不变,等待下次Trigger fire的时候再次执行计算。一个窗口可以被重复计算多次直到它被 purge 了。在purge之前,窗口会一直占用着内存。

3、当Trigger fire了,窗口中的元素集合就会交给Evictor(如果指定了的话)。Evictor 主要用来遍历窗口中的元素列表,并决定最先进入窗口的多少个元素需要被移除。剩余的元素会交给用户指定的函数进行窗口的计算。如果没有 Evictor 的话,窗口中的所有元素会一起交给函数进行计算。

4、计算函数收到了窗口的元素(可能经过了 Evictor 的过滤),并计算出窗口的结果值,并发送给下游。窗口的结果值可以是一个也可以是多个。DataStream API 上可以接收不同类型的计算函数,包括预定义的sum(),min(),max(),还有 ReduceFunctionFoldFunction,还有WindowFunction。WindowFunction 是最通用的计算函数,其他的预定义的函数基本都是基于该函数实现的。

5、Flink 对于一些聚合类的窗口计算(如sum,min)做了优化,因为聚合类的计算不需要将窗口中的所有数据都保存下来,只需要保存一个result值就可以了。每个进入窗口的元素都会执行一次聚合函数并修改result值。这样可以大大降低内存的消耗并提升性能。但是如果用户定义了 Evictor,则不会启用对聚合窗口的优化,因为 Evictor 需要遍历窗口中的所有元素,必须要将窗口中所有元素都存下来。

 

posted @ 2019-12-13 10:34  再见傅里叶  阅读(564)  评论(0编辑  收藏  举报