flink 1.13 event时间不触发窗口问题记录

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在窗口中引入watermark,使用EventTime,传入数据时不触发窗口的结束。也是自己平时不注意细节导致踩了一个很‘憨’的坑。
flink 初学者,有问题欢迎讨论


一、问题记录

1.出错代码

代码如下(示例):

 val env = StreamExecutionEnvironment.getExecutionEnvironment

    env.setParallelism(1)

    //watermark默认生成时间为200ms
   // env.getConfig.setAutoWatermarkInterval(200)


    val df = env.socketTextStream("82.156.186.40", 6666)

    //数据格式:1,9,1547718210
    val fdf = df.map(row => {
      val a: Array[String] = row.split(",")
      (a(0), a(1).toInt, a(2).toLong)
    })
      .assignTimestampsAndWatermarks(WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(5))
        .withTimestampAssigner(new SerializableTimestampAssigner[(String, Int, Long)] {
        override def extractTimestamp(element: (String, Int, Long), recordTimestamp: Long): Long = {
          element._3
        }
      }))
      .keyBy(data => data._1)
      .window(TumblingEventTimeWindows.of(Time.seconds(10)))
      .allowedLateness(Time.minutes(1))
      .sideOutputLateData(lateTag)
      .reduce((o, n) => {
        (o._1, Math.min(o._2, n._2), n._3)
      })
    //上述代码逻辑
    //10秒一个窗口 watermark200ms生成一次,watermark最大容错率为5s

    //打印迟到数据
    fdf.getSideOutput(lateTag).print("late")
    //打印窗口数据
    fdf.print("result")

    env.execute()

2.输入数据

输入数据如下(示例):

1,1,1547718201
1,2,1547718210
1,3,1547718211
1,4,1547718212
1,5,1547718215
1,6,1547718221
1,7,1547718215
1,8,1547718231

输入的数据
运行结果

可以看到上面我输入的数据最大的相差时间有30s,但是所有数据输入完后没有任何一个窗口被激发,并且我设置了最大线程数为1,也不存在,因为我数据少导致某个分区watermark取不到的问题。
既然如此开始传统艺能看看源码,我们知道窗口什么时候关闭是由watermark决定的来看一下BoundedOutOfOrdernessWatermarks的生成策略

public class BoundedOutOfOrdernessWatermarks<T> implements WatermarkGenerator<T> {

    //记录最大时间戳
    private long maxTimestamp;

    //最大乱序程度
    private final long outOfOrdernessMillis;

    /**
     * Creates a new watermark generator with the given out-of-orderness bound.
     *
     * @param maxOutOfOrderness The bound for the out-of-orderness of the event timestamps.
     */
    public BoundedOutOfOrdernessWatermarks(Duration maxOutOfOrderness) {
        checkNotNull(maxOutOfOrderness, "maxOutOfOrderness");
        checkArgument(!maxOutOfOrderness.isNegative(), "maxOutOfOrderness cannot be negative");

        this.outOfOrdernessMillis = maxOutOfOrderness.toMillis();

        // start so that our lowest watermark would be Long.MIN_VALUE.
        this.maxTimestamp = Long.MIN_VALUE + outOfOrdernessMillis + 1;
    }

    // ------------------------------------------------------------------------
	//每一个数据处理时 都会调用该方法,在这里用于更新最大时间戳,记录你处理过的数据中最大的时间戳
    @Override
    public void onEvent(T event, long eventTimestamp, WatermarkOutput output) {
        maxTimestamp = Math.max(maxTimestamp, eventTimestamp);
    }
	//周期行调用的方法 默认为200ms,该方就是生成watermark的方法
	//从该方法中我们可以看到 每次生成的水位线的时间为:
	//maxTimestamp - outOfOrdernessMillis - 1
	//maxTimestamp 为我们所记录的最大时间戳
	//outOfOrdernessMillis是我们设置的最大乱序程度
	//最后为什么要减一呢?举个例子,时间乱序度忽略不计,当前时间戳为1547718231,转换为毫秒为1547718231000,如果只来了一条这个数据,就判定为watermark为1547718231000,那么后面来的数据时间为1547718231000的数据不就全迟到了?
    @Override
    public void onPeriodicEmit(WatermarkOutput output) {
        output.emitWatermark(new Watermark(maxTimestamp - outOfOrdernessMillis - 1));
    }
}

看上面的代码我们可以发现
this.outOfOrdernessMillis = maxOutOfOrderness.toMillis();
将我们设置的最大乱序程度转为了毫秒进行处理,而我们提取的时间戳为秒级别,输入数据的最大时间戳为1547718231,那么最后生成的watermark为1547713231,所以没有触发窗口的关闭


3.解决问题

在这里插入图片描述
在提取时间的时候将时间戳转化为毫秒就行了QAQ

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值