flink时间系统系列篇幅目录:
一、时间系统概述介绍
二、Processing Time源码分析
三、Event Time源码分析
四、时间系统在窗口函数中的应用分析
五、ProcessFunction 使用分析
六、实例讲解:如何做定时输出
上一篇幅中对processing Time的整个注册流程与调用流程做了整体分析,并且分析了Flink中时间系统管理涉及的核心类,此篇幅将会介绍Event Time如何注册定时、定时如何触发。
Flink 中ProcessFunction 注册EventTime 定时是通过registerEventTimeTimer方式、在event-time 窗口中由flink内部帮助我们完成这项工作,注册过程与Processing Time大体一样,主要也是通过一个优先级队列来完成,先看下其调用链:
其内部仅仅是调用了这一个方法,传的参数是namespace/time,会将time(触发定时器的时间)/key(从keyContext中获取)/namespace(窗口中是window对象、非窗口中是VoidNamespace对象) 构造成为一个TimerHeapInternalTimer对象,然后将其放入KeyGroupedInternalPriorityQueue 按照时间排序升序排序的优先级队列,同样会忽略相同key/time/namespace的加入;
注册相对比较简单,那么注册之后是如何触发的,在processing time 中触发是通过系统定时来触发的,Event Time的触发则是通过watermark 来决定的,当定时生成的watermark大于等于注册的时间,就会触发定时操作,先看下其调用链:
AbstractStreamOperator.processWatermark所有的watermark 进入一个算子中都需要调用该方法,在该方法中按顺序做两件事情
一:调用该operator 的InternalTimeServiceManager.advanceWatermark方法
二:output.emitWatermark 将该watermark发送到下一个节点,这里额外做一个知识点说明,这个调用顺序其实就解释了为什么两个连续窗口的操作,第二个窗口能够正好获取到第一个窗口的结果数据,窗口的触发是需要watermark大于等于窗口endTime , 两个连续窗口中第一个窗口触发,先处理窗口数据发送到下一个节点,数据的时间(event-time)是窗口的endTime,而后在发送watermark到下一个节点,发送数据到第二个窗口正好与第一个窗口具有相同的endTime, 正好触发第二个窗口操作,在这里始终需要记住一点,watermark进入操作流中是先处理数据然后在发送watermark;
具体watermark触发什么样的操作在InternalTimeServiceManager.advanceWatermark中,在该方法中会循环遍历其所拥有的InternalTimerServiceImpl对象的advanceWatermark方法,在该对象中有KeyGroupedInternalPriorityQueue 存放注册的event-time 的所有定时器数据,在advanceWatermark方法中循环遍历该队列
如果注册的时间小于等于watermark, 那么就会调用Triggerable.onEventTime方法,Triggerable表示具体定时操作接口,例如WindowOperator/KeyedProcessOperator 都实现了该接口。
以上就是event-time的整个注册与调用流程,最好能够对照源码多看几遍。