Flink 调试watermark & allowedLateness

调试watermark & allowedLateness

  • 基本概念
  • 能明白什么
  • 开始调试
  • 总结

基本概念

  • watermark 主要是为了解决数据乱序到达的问题
  • allowed 解决窗口触发后数据迟到后的问题

能明白什么

  • 窗口的范围
  • 窗口的触发条件
  • 窗口的销毁时间
  • 迟到元素的处理方式
  • watermark的生成方式

开始调试

  • 代码准备 Flink
package com.wending.demo;

import com.alibaba.fastjson.JSONObject;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.AssignerWithPeriodicWatermarks;
import org.apache.flink.streaming.api.watermark.Watermark;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;

import javax.annotation.Nullable;

/**
 * date 2019/6/16
 */
public class KafkaWaterMark {

    public static void main(String[] args) {
        StreamExecutionEnvironment en = StreamExecutionEnvironment.getExecutionEnvironment();
        en.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
        en.getConfig().setAutoWatermarkInterval(5000);
        en.enableCheckpointing(5000);
        KafkaUtil util = new KafkaUtil();
        // 自己封装
        FlinkKafkaConsumer011 consumer = util.getConsumer("stream2", "test4");
        en.setParallelism(1);
        en.addSource(consumer).assignTimestampsAndWatermarks(new ass()).map(new MapFunction() {
            @Override
            public Tuple2 map(Object o) throws Exception {
                String value = JSONObject.parseObject((String) o).getString("word");
                System.out.println("value is " + value);
                return new Tuple2<>(value, 1);
            }
        }).returns(Types.TUPLE(Types.STRING, Types.INT)).keyBy(0)
                .window(TumblingEventTimeWindows.of(Time.seconds(10)))
                .allowedLateness(Time.seconds(2))   // 最多允许迟到2s
                .sum(1)
                .print();
        try {
            en.execute("mark-test");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class ass implements AssignerWithPeriodicWatermarks {

    long maxOutOfOrderness = 6000;
    private long currentMaxTimestamp;

    @Override
    public long extractTimestamp(Object element, long previousElementTimestamp) {
        long createtime = 0L;
        if (element != null) {
            try {
                createtime = JSONObject.parseObject((String) element).getLong("createTime");
                System.out.println("extrac" + createtime);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        currentMaxTimestamp = Math.max(createtime, currentMaxTimestamp);
        return createtime;
    }

    @Nullable
    @Override
    public Watermark getCurrentWatermark() {
        System.out.println("watermark" + (currentMaxTimestamp - maxOutOfOrderness));
        return new Watermark(currentMaxTimestamp - maxOutOfOrderness);
    }
}

watermark 生成方式,抽取消费里的createTime,单调递增

  • 代码准备 producer 自己实现吧,很简单的
  • 调试结果
createtime watermark value assign window print result note
1562419080000 (2019-07-06 21:18:00) 1562419074000 aa [18:00-18:10) aa
1562419085000 (2019-07-06 21:18:05) 1562419079000 aa [18:00-18:10) aa
1562419090000 (2019-07-06 21:18:10) 1562419084000 bb [18:10-18:20) bb
1562419089000 (2019-07-06 21:18:09) 1562419084000 bb [18:00-18:10) bb
1562419096000 (2019-07-06 21:18:16) 1562419090000 aa [18:10-18:20) (aa ,2) (bb,1) 触发窗口计算了 watermark> window.max()
1562419097000 (2019-07-06 21:18:17) 1562419091000 bb [18:10-18:20) bb
1562419080000 (2019-07-06 21:18:00) 1562419091000 aa [18:00-18:10) (aa,3) 这是一个迟到的元素,此时的watermark还小于18:12 还能触发
1562419080000 (2019-07-06 21:18:00) 1562419091000 bb [18:00-18:10) (bb,2) 这是一个迟到的元素,此时的watermark还小于18:12 还能触发
1562419098000 (2019-07-06 21:18:18) 1562419092000 bb [18:10-18:20) bb 现在的watermark> 18:12 了
1562419080000 (2019-07-06 21:18:00) 1562419092000 aa [18:00-18:10) 触发不了,之前的窗口已经销毁了

总结

  • 窗口的范围

以Ms,10s来看,一个窗口的范围就是1562419080000 - 1562419089999

  • 窗口的触发条件

窗口内有数据,watermark>1562419089999 以就是窗口的max,才能触发,也就是说 window 在[18:00-18:10) 的数据实际上是得到creattime在18:16才能触发,所以说这个窗口到到达的数据 18:00<=creattime <18:10只需在18:00<=creattime <18:16到达即可,不用管顺序

  • 窗口的销毁时间

如果没有设置allowedLateness,窗口触发就销毁,设置了的话,watermark>window.max+allowedLateness 即销毁

  • 迟到元素的处理方式

可以设置allowedLateness,再等等迟到的元素

  • watermark的生成方式

参考 生成watermark

你可能感兴趣的:(Flink,Flink,入门到实践)