在上篇文章中,我详细讨论了 Flink 是如何为 record 分配窗口的。接下来我们就要讨论一下什么时机触发对窗口的计算了。这就像响指的功能,当集齐五个石头后,什么时候毁灭宇宙一半的生命呢?大家都知道了, 还差一个响指。我们今天讨论的触发时机,和响指的功能差不多,在 Flink 中,Flink 的开发者给他起了一个非常形象的名字——Trigger。
请看下面的图片, Trigger 就是手枪的扳机。扳动扳机就能射出子弹,在 Flink 里面,Trigger 类决定了,是否对窗口中的数据进行计算,并将计算结构发到后面的算子。

比喻说完了,下面进入到正题。
正题
总体流程
有一个类是 Trigger 类,window 该不该触发计算,是由它决定的。它返回一个 TriggerResualt 这样的一个 Enumerate 。 当它的值为 Fire 的时候,就会触发窗口的计算。
想要弄清楚 Trigger 是怎么触发的,就涉及到 WindowOperator 和 Trigger(以 EventTimerTrigger 为例),还有 InternalTimeServerImpl 这几个类的调用关系。
我是看了 Flink 的官方文档,知道有 Trigger 这货的,然后我用 ideal 来看的源码,再加上打断点,终于搞清楚这几个的调用过程。调用的过程如下所示:

InternalTimeServerImpl 是 Flink 的一个定时器实现,如果调用它的 registerEventTimeTimer,注册一个定时时间(可以比作闹钟),等到了时间,InternalTimeServerImpl 会调用 WindowOperator 的 onElement() 函数,WindowOperator 的 onEventTime 方法中也调用了 Trigger 的 onEventTime() 方法,当 onEventTime() 返回 fire 这种 TriggerResualt 的时候,就会触发窗口的计算。
另外一个调用 trigger 的时间是当有新的元素进入到窗口后,WindowOperator 会调用 trigger.onElement 的方法,当 trigger 返回 fire 类型的 triggerResult 后,就要触发窗口的计算。
总体的代码执行逻辑说完了,接下来,我就要从细节上,结合测试数据来看一下,代码的执行过程。
下面我就来描述一下。我们重点来看一下 EventtimeTrigger里面的逻辑。
流程中的细节
使用一个案例来说明 trigger 的作用:
import org.apache.flink.api.common.ExecutionConfig;
import org.apache.flink.api.common.eventtime.*;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple6;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.AssignerWithPeriodicWatermarks;
import org.apache.flink.streaming.api.functions.windowing.WindowFunction;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.triggers.Trigger;
import org.apache.flink.streaming.api.windowing.triggers.TriggerResult;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;
import javax.annotation.Nullable;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* @className: WaterMarkTest
* @Description:
* @Author: wangyifei
* @Date: 2024/4/7 17:26
*/
public class WaterMarkTest {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
ExecutionConfig config = env.getConfig();
// 默认的 autoWatermarkInterval 的时间是 200 ms
// config.setAutoWatermarkInterval(2000L);
// 并发度的设置是必须的,如果 assignerTimestampAndWatermark() 返回的 DataStream 的并发度大于后面窗口的并发度,
// 则 DataStream 总会有一个分区的时间戳为 0 ,到了窗口中是取最小的那个, 就是 0 了,这样的话就不能触发窗口的计算了。
config.

本文深入探讨了Flink中的窗口触发机制,包括Trigger的概念、触发条件及不同类型的Trigger工作原理,如EventtimeTrigger、ContinuousEventTimeTrigger等,并通过实例代码展示了如何实现窗口计算的触发。
最低0.47元/天 解锁文章
1427

被折叠的 条评论
为什么被折叠?



