Flink个人学习整理-WaterMark篇(六)

Flink个人学习整理-WaterMark篇(六)

1、Flink中的时间语义
1.12之前时间语义分为3种
I、处理时间(默认)
II、事件时间
III、数据进入时间
在这里插入图片描述

1.12进行了更改 时间语义合并为2种
I、处理时间
II、事件时间(默认)
在这里插入图片描述
处理时间
处理时间是指的执行操作的各个设备的时间。
处理时间是最简单时间语义, 数据流和设备之间不需要做任何的协调.。
他提供了最好的性能和最低的延迟.。但是, 在分布式和异步的环境下, 处理时间没有办法保证确定性, 容易受到数据传递速度的影响: 事件的延迟和乱序

事件时间
事件时间是指的这个事件发生的时间。
在事件时间体系中, 时间的进度依赖于数据本身, 和任何设备的时间无关。作用就相当于现实时间的时钟
注意:
在1.12之前默认的时间语义是处理时间, 从1.12开始, Flink内部已经把默认的语义改成了事件时间
WaterMark是一条特殊的数据,时间戳

watermark作用:
1、处理乱序问题。(通过延迟关窗)
2、在系统中会认为小于等于该事件时间的已经全部到齐,其内部会减1毫秒,单调递增。
在乱序流中,需要通过设置延迟时间,延迟通过数据间的最大时间差确定。
自定义WaterMark,有两种周期型(periodic)默认每200ms生成一个、间歇性(punctuated)每条数据生成一个

水位线策略:WaterStrategy
自增:.< T >forMonotonousTimestamps
乱序延迟:< T >forBoundedOutOfOrderness

public class Flink_Time_EventTumblingWindows {
    public static void main(String[] args) throws Exception {
        //  获取运行时环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);


        //  设置水位线生成器,为自增类型 允许延迟为0
        WatermarkStrategy<Sensor> waterSensorWatermarkStrategy = WatermarkStrategy.<Sensor>forMonotonousTimestamps()
                //  分配时间戳
                .withTimestampAssigner(new SerializableTimestampAssigner<Sensor>() {
                    @Override
                    public long extractTimestamp(Sensor element, long recordTimestamp) {
                        //  因为数据时间戳是10位 为s,watermark需要的是毫秒。因此 * 1000
                        return element.getTs() * 1000L;
                    }
                });
        //  设置水位线生成器,为乱序,增加延迟2s,延迟不会改变数据在哪个窗口,只会延迟窗口的关闭
        //  延迟通过数据间的最大时间差确定。
        WatermarkStrategy<Sensor> waterSensorWatermarkStrategy1 = WatermarkStrategy.<Sensor>forBoundedOutOfOrderness(Duration.ofSeconds(2))
                .withTimestampAssigner(new SerializableTimestampAssigner<Sensor>() {
                    @Override
                    public long extractTimestamp(Sensor element, long recordTimestamp) {
                        //  因为数据时间戳是10位 为s,watermark需要的是毫秒。因此 * 1000
                        return element.getTs() * 1000L;
                    }
                });

        env.socketTextStream("localhost",9999)
                //  将数据转化为JavaBean
                .map(new MapFunction<String, Sensor>() {
                    @Override
                    public WaterSensor map(String value) throws Exception {
                        String[] strings = value.split(",");
                        return new Sensor(
                                strings[0],
                                Long.parseLong(strings[1]),
                                Integer.parseInt(strings[2]));
                    }
                })
                //  提取数据中的时间戳字段
                .assignTimestampsAndWatermarks(waterSensorWatermarkStrategy1)
                .keyBy(new KeySelector<Sensor, String>() {
                    @Override
                    public String getKey(Sensor value) throws Exception {
                        return value.getId();
                    }
                })
                .window(TumblingEventTimeWindows.of(Time.seconds(5)))
                .sum("vc")
                .print("Event-TumblingWindow");

        env.execute();
    }
}

保障数据完整性:
1、水位线策略:乱序延迟:< T >forBoundedOutOfOrderness
2、允许迟到数据,增量计算
3、侧输出流

public class Flink_Time_EventTumbling_LastAndSideOutPut {
    public static void main(String[] args) throws Exception {
        //  获取运行时环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        SingleOutputStreamOperator<Sensor> result = env.socketTextStream("localhost", 9999)
                .map(new MapFunction<String, Sensor>() {
                    @Override
                    public Sensor map(String value) throws Exception {
                        String[] strings = value.split(",");
                        return new Sensor(
                                strings[0],
                                Long.parseLong(strings[1]),
                                Integer.parseInt(strings[2])
                        );
                    }
                })
                //  设置水位线模式,延迟
                .assignTimestampsAndWatermarks(WatermarkStrategy.<Sensor>forBoundedOutOfOrderness(Duration.ofSeconds(2))
                        .withTimestampAssigner(new SerializableTimestampAssigner<Sensor>() {
                            @Override
                            public long extractTimestamp(Sensor element, long recordTimestamp) {
                                //  因为数据是10位时间戳,然而水位线需要的是ms,*1000L
                                return element.getTs() * 1000L;
                            }
                        }))
                .keyBy(new KeySelector<Sensor, String>() {
                    @Override
                    public String getKey(Sensor value) throws Exception {
                        return value.getId();
                    }
                })
                .window(TumblingEventTimeWindows.of(Time.seconds(5)))
                //  配置允许迟到数据 2s内 数据变为增量计算  在WaterMark基础上再延迟2s
                .allowedLateness(Time.seconds(2))
                //  注意写:{}
                .sideOutputLateData(new OutputTag<Sensor>("Site"){})
                .sum("vc");

        //  正常数据流
        result.print();

        //  侧输出流  窗口关闭后,延迟的数据每条数据依次输出
        //  注意写:{}
        DataStream<Sensor> site = result.getSideOutput(new OutputTag<Sensor>("Site"){});
        site.print("Site");

        env.execute();
    }
}

自定义WaterMark
1、周期型
2、间歇型

public class Flink_Time_EventTumblingWindows_CustomerPeriod {
    public static void main(String[] args) throws Exception {
        //  获取运行时环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        //  设置WaterMark自动提交时间
        //	env.getConfig().setAutoWatermarkInterval(500L);

        //  自定义WaterMark
        WatermarkStrategy<Sensor> watermarkStrategy = new WatermarkStrategy<Sensor>() {
            @Override
            public WatermarkGenerator<Sensor> createWatermarkGenerator(WatermarkGeneratorSupplier.Context context) {
                //  延迟2s
                return new MyPeriod(2000L);
            }
        }.withTimestampAssigner(new SerializableTimestampAssigner<Sensor>() {
            @Override
            public long extractTimestamp(Sensor element, long recordTimestamp) {
                return element.getTs()*1000L;
            }
        });

        env.socketTextStream("localhost",9999)
                //  将数据转化为JavaBean
                .map(new MapFunction<String, Sensor>() {
                    @Override
                    public Sensor map(String value) throws Exception {
                        String[] strings = value.split(",");
                        return new Sensor(
                                strings[0],
                                Long.parseLong(strings[1]),
                                Integer.parseInt(strings[2]));
                    }
                })
                //  提取数据中的时间戳字段
                .assignTimestampsAndWatermarks(watermarkStrategy)
                .keyBy(new KeySelector<Sensor, String>() {
                    @Override
                    public String getKey(Sensor value) throws Exception {
                        return value.getId();
                    }
                })
                .window(TumblingEventTimeWindows.of(Time.seconds(5)))
                .sum("vc")
                .print("Event-TumblingWindow周期型的WaterMark");

        env.execute();
    }

    //  自定义周期型的WaterMark生成器
    public static class MyPeriod implements WatermarkGenerator<Sensor>{

        //  不能直接在这赋值为Long的最小值,如果设置后就变为了MINLONG-一个数,那么就会变为MAXLONG
        private Long maxTs;
        //  延迟时间
        private Long maxDelay = 0L;

        public MyPeriod(Long maxDelay) {
            this.maxDelay = maxDelay;
            this.maxTs = Long.MIN_VALUE + maxDelay + 1;
        }

        //  当数据来的时候调用
        @Override
        public void onEvent(Sensor event, long eventTimestamp, WatermarkOutput output) {
            maxTs = Math.max(eventTimestamp,maxTs);
        }

        //  周期性的把WaterMark发射出去, 默认周期是200ms
        @Override
        public void onPeriodicEmit(WatermarkOutput output) {
            output.emitWatermark(new Watermark(maxTs-maxDelay));
        }
    }

}
public class Flink_Time_EventTumblingWindows_CustomerPunct {
    public static void main(String[] args) throws Exception {
        //  获取运行时环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        //  自定义WaterMark
        WatermarkStrategy<Sensor> watermarkStrategy = new WatermarkStrategy<Sensor>() {
            @Override
            public WatermarkGenerator<Sensor> createWatermarkGenerator(WatermarkGeneratorSupplier.Context context) {
                //  延迟2s
                return new MyPunct(2000L);
            }
        }.withTimestampAssigner(new SerializableTimestampAssigner<Sensor>() {
            @Override
            public long extractTimestamp(Sensor element, long recordTimestamp) {
                return element.getTs()*1000L;
            }
        });

        env.socketTextStream("localhost",9999)
                //  将数据转化为JavaBean
                .map(new MapFunction<String, Sensor>() {
                    @Override
                    public Sensor map(String value) throws Exception {
                        String[] strings = value.split(",");
                        return new Sensor(
                                strings[0],
                                Long.parseLong(strings[1]),
                                Integer.parseInt(strings[2]));
                    }
                })
                //  提取数据中的时间戳字段
                .assignTimestampsAndWatermarks(watermarkStrategy)
                .keyBy(new KeySelector<Sensor, String>() {
                    @Override
                    public String getKey(Sensor value) throws Exception {
                        return value.getId();
                    }
                })
                .window(TumblingEventTimeWindows.of(Time.seconds(5)))
                .sum("vc")
                .print("Event-TumblingWindow间歇性的WaterMark");

        env.execute();
    }

    //  自定义间歇性的WaterMark生成器
    public static class MyPunct implements WatermarkGenerator<Sensor>{

        //  不能直接在这赋值为Long的最小值,如果设置后就变为了MINLONG-一个数,那么就会变为MAXLONG
        private Long maxTs;
        //  延迟时间
        private Long maxDelay = 0L;

        public MyPunct(Long maxDelay) {
            this.maxDelay = maxDelay;
            this.maxTs = Long.MIN_VALUE + maxDelay + 1;
        }

        //  当数据来的时候调用
        @Override
        public void onEvent(Sensor event, long eventTimestamp, WatermarkOutput output) {
            maxTs = Math.max(eventTimestamp,maxTs);
            output.emitWatermark(new Watermark(maxTs-maxDelay));
        }

        //  周期性的把WaterMark发射出去, 默认周期是200ms
        @Override
        public void onPeriodicEmit(WatermarkOutput output) {
        }
    }
}

非1并行度下WaterMark的传递问题
在这里插入图片描述
WaterMark传递机制
1、WaterMark是向下游广播的
2、在多并行度条件下,下游接收多个WaterMark,以最小的那个为准
注意:在Source后和Map后提取WaterMark所造成的结果是不一样的
3、当WaterMark值没有增长的时候,不会向下游传递,生成不变

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值