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

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

文章目录

  • 前言
  • 一、问题记录
    • 1.出错代码
    • 2.输入数据
    • 3.解决问题


前言

在窗口中引入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

flink 1.13 event时间不触发窗口问题记录_第1张图片
运行结果

可以看到上面我输入的数据最大的相差时间有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.解决问题

flink 1.13 event时间不触发窗口问题记录_第2张图片
在提取时间的时候将时间戳转化为毫秒就行了QAQ

你可能感兴趣的:(flink,大数据,big,data)