Flink基础5篇-4-基于时间和窗口的算子
配置时间特性
在DataStreamAPI中,可以使用时间特性告知flink在创建窗口的时候如何定义时间
此处可以传入三种值
- ProcessingTime:处理时间,由处理机器的系统时间决定
- EventTime:根据数据自身包含的信息决定当前时间
- IngestionTime:使用处理时间同时自动生成水位线,意义不大
分配时间戳和水位线
有两种方法分配时间戳和生成水位线
- 直接在sourceFunction中定义
- 显式的使用一个用户自定义的时间戳分配及水位线生成器
todo: 第一种,在第八章
对于第二种:
TimestampAssinger 接口,用于从数据中提取时间戳。应该在数据源函数后面立即调用分配器。
通过assignTimestampAndWatermarks方法传入自定义的分配器。
对于自定义的分配器,可以周期性的生成水位线(AssignerWithPeriodicWatermarks),也可以根据输入事件的属性生成水位线(AssignerWithPunctuatedWatermarks)
周期性水位线分配器
以固定的时间间隔发送水位线,默认200ms
定点水位线分配器
如果输入流中包含了一些用于指示系统进度的特殊标记,可以使用定点水位线生成,即根据输入元素的特点来生成水位线。在AssignerWithPunctuatedWatermarks接口中,checkAndGetNextWatermark方法会在提取时间戳后立刻调用,决定是否生成一个新的水位线。如果返回一个非空且大于之前水位线的值,算子就会发出一个新的水位线。
水位线、延迟和完整性问题
水位线用于平衡延迟和完整性,水位线间隔设置太大,完整性会提升,但延迟会加大。间隔设置太小,延迟很低,但完整性减小。应根据具体数据的产生和传输情况,估计延迟的上限,根据此定义水位线。
处理函数
基础的DataStreamAPI无法访问时间戳和水位线。
处理函数可以访问记录的时间戳和水位线,提供以下功能:
- 注册将来某个特定时间触发的计时器
- 副输出功能允许将记录发送到多个流中
处理函数主要用于构建事件驱动型应用,实现一些内置窗口无法实现的功能。
针对不同的上下文环境(不同的流),flink提供了8中处理函数
ProcessFunct ion、Keyed ProcessFunction, CoProcessFunction, ProcessJoinFunction, Broadcast ProcessFunction. KeyedBroadcastProcessFunction, ProcessWindowFunction和
ProcessAllWindowFunction
它们的通用功能如下:
- 对每条记录进行调用,返回一条或多条记录
- 回调函数,在计时器触发时调用
- 查看水位线,时间戳
- 注册或删除计时器
看下面这个例子,如果传感器的温度在1s内持续上升,则告警(基于事件驱动,内置窗口无法实现)
处理函数还支持从同一个函数发出多条数据流,且它们的类型可以不同。每个副输出都由一个outputTag[X]对象标记。
窗口算子
窗口算子提供了一种基于有限大小的桶对事件进行分组,并对桶中的有限数据进行计算的方法。
内置窗口分配器
基于时间的窗口分配器会根据元素事件时间或处理时间将其分配到一个或多个窗口,每个窗口有开始时间戳和结束时间戳。
窗口会随系统首次分配元素而创建,flink不会对空窗口执行计算。
滚动窗口
滚动窗口分配器会将元素放入大小固定且互不重叠的窗口中
滑动窗口
滑动窗口分配器将元素分配给大小固定且按指定滑动间隔移动的窗口
需要指定窗口大小和滑动间隔
会话窗口
会话窗口将元素放入长度可变且不重叠的窗口中。需要定义非活动间隔,即持续没有收到元素的时间间隔。
在窗口上应用函数
可用于窗口的函数有两种
- 增量聚合:在窗口内以状态的形式存储某个值,且需要根据每个加入窗口的元素更新状态。如ReduceFunction,aggregateFunction
- 全量窗口函数:会收集所有元素,并在执行时进行遍历。如ProcessWindowFunction
可以组合使用上述两种函数,可以对分配给窗口的元素立即执行聚合,随后当窗口触发器触发时,将聚合后的结果传给processwindowfunction。具体来讲,将processWindowFunction作为reduce或aggregate方法的第二个参数
自定义窗口算子
DataStreamAPI对外暴露了自定义窗口算子的接口和方法。可以自己实现分配器,触发器和移除器。
当元素进入窗口算子时会被移交给windowAssigner,决定将元素放入哪个窗口。
如果为窗口算子配置了增量聚合函数,则立即进行一次计算,更新状态。如果没有增量函数,则将元素附加到ListStae上。触发器定义了窗口何时准备好计算。
配置了增量聚合函数的算子执行过程:
配置了全量窗口函数的算子执行过程:
配置了组合函数的算子执行过程:
- 移除器是一个可选组件,允许在全量函数执行前或后引入,可以从窗口中删除已收集的元素。移除器只在没有增量函数的情况下使用。
窗口的生命周期
WindowAssigner决定将元素分配给哪些窗口
触发器
用于定义何时对窗口进行计算并发出结果。触发逻辑可以在触发器中自定义。每次调用触发器都生成一个TriggerResult,这个结果决定窗口的后续动作:
一个可选组件,用于在窗口执行计算前或者后从窗口中删除元素
基于时间的双流JOIN
将两条数据流进行联结,Flink根据时间条件支持两种联结算子:
对两条流中拥有相同键值且彼此时间间隔不超过某个指定间隔的事件进行JOIN
基于间隔的JOIN需要对两条流进行缓存,
将两条流的数据分配到公共窗口中,在窗口完成时进行JOIN
当窗口触发时,算子会遍历两条输入流中元素的每一种组合,调用JoinFunction
处理迟到数据
迟到数据是在相应水位线之后到来的数据。即本应参与的计算已经完成了。
DataStream API提供三种处理方法
是默认行为,不会创建新的窗口。
重定向迟到事件
利用副输出将迟到事件重定向。后续进行单独处理,可以做定期的数据回填。
更新计算结果
窗口算子API提供一个方法,可以显式声明支持迟到元素。在使用事件窗口时,可以指定一个名为延迟容忍度(allowed lateness)的额外时间段。如果配置了,则当水位线超过窗口的结束时间时,窗口不会立即被删除。而是保留到容忍度之后。这段时间到达的元素可以正常处理。
当水位线超过了容忍度后,窗口关闭,再迟到的元素丢弃处理。
相当于在水位线上再加一层延迟。