flink延迟数据处理

flink延时数据处理

 

flink延时数据处理,我们第一时间想到的是watermark,但是watermark真的能够完全解决数据延时问题吗?肯定是不能。

通常对于延时数据的处理分为3种方式:

1.直接丢弃,少量的数据丢失或许并不影响结果,毕竟离线的时候还会处理

2.把迟到的部分,单独在开一个window处理

3.把数据符合要求的部分,在导入到窗口中

下面是一篇博客的详细讲述1,2情况。

参考:https://blog.csdn.net/yangxiaobo118/article/details/100173001

Flink笔记-延迟数据处理
Out Of Order&Late
AllowedLateness&OutputTag
关于测输出(OutputTag)

Flink的窗口处理流式数据虽然提供了基础EventTime的WaterMark机制,但是只能在一定程度上解决数据乱序问题。而某些极端情况下数据延迟会非常严重,即便通过WaterMark机制也无法等到数据全部进入窗口再进行处理。默认情况下,Flink会将这些严重迟到的数据丢弃掉;如果用户希望即使数据延迟到达,也能够按照流程处理并输出结果,此时可以借助Allowed Lateness机制来对迟到的数据进行额外的处理。
Out Of Order&Late
其都是为了处理乱序问题而产生的概念,区别如下:

通过watermark机制来处理out-of-order的问题,属于第一层防护,属于全局性的防护,通常说的乱序问题的解决办法,就是指这类;
通过窗口上的allowedLateness机制来处理out-of-order的问题,属于第二层防护,属于特定window operator的防护,late element的问题就是指这类。
AllowedLateness&OutputTag
DataStream API提供了allowedLateness方法来指定是否对迟到数据进行处理,指定后,Flink窗口计算过程中会将window的Endtime加上该时间作为窗口最后被释放的时间,当接入的数据中EventTime未超过窗口最后被释放的时间,但WaterMark已经超过Window的EndTime时,直接触发窗口计算。相反,如果事件时间超过了窗口最后被释放的时间(最大延时时间),则只能对数据进行丢弃处理。
默认情况下,GlobleWindow的最大Lateness时间为Long.MAX_VALUE,即不超时,因此数据会源源不断累积到窗口中,等待被触发。

demo

/**
 * @author qingh.yxb
 * @since 2019/9/7
 */
public class AllowLateness {
    // def OutputTag
    private static final OutputTag<Tuple2<String, Integer>> myTag = new OutputTag<Tuple2<String, Integer>>("myTag") {
    };
    public static void main(String[] args) throws Exception {
        List<Tuple2<String, Integer>> source = Lists.newArrayList();
        source.add(new Tuple2<>("qingh1", 1));
        source.add(new Tuple2<>("qingh2", 2));
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Tuple2<String, Integer>> dataStreamSource = env.fromCollection(source);

        env.enableCheckpointing(20000, CheckpointingMode.EXACTLY_ONCE);
        //env.enableCheckpointing(20000);
        env.getCheckpointConfig() //  清除策略
                .enableExternalizedCheckpoints(CheckpointConfig.
                        ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
        env.setRestartStrategy(RestartStrategies.
                fixedDelayRestart(3,
                        10000));
        env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
        SingleOutputStreamOperator<String> result = dataStreamSource.assignTimestampsAndWatermarks(
                new AssignerWithPunctuatedWatermarks<Tuple2<String, Integer>>() {
                    @Nullable
                    @Override
                    public Watermark checkAndGetNextWatermark(Tuple2<String, Integer> lastElement, long extractedTimestamp) {
                        return new Watermark(System.currentTimeMillis()-500);
                    }

                    @Override
                    public long extractTimestamp(Tuple2<String, Integer> element, long previousElementTimestamp) {
                        return System.currentTimeMillis()-1000;
                    }
                }
        ).keyBy(new KeySelector<Tuple2<String, Integer>, String>() {
            @Override
            public String getKey(Tuple2<String, Integer> value) throws Exception {
                return "key";
            }
        }).timeWindow(Time.milliseconds(10)).allowedLateness(Time.milliseconds(10)).
                sideOutputLateData(myTag)
                //.sum(1);
                .process(new ProcessWindowFunction<Tuple2<String, Integer>, String, String, TimeWindow>(){
                    @Override
                    public void process(String s, Context context, Iterable<Tuple2<String, Integer>> elements, Collector<String> out) throws Exception {
                        for (Tuple2<String, Integer> element : elements) {
                            out.collect(element.f0);
                        }
                    }
                });
        DataStream<Tuple2<String, Integer>> sideOutput = result.getSideOutput(myTag);
        //只输出outPutTag中内容
        sideOutput.print();
        env.execute("qinghh Demo");
    }
}
测试结果:

为什么第一条数据没有被展示出来?问题好像在这里org.apache.flink.streaming.api.operators.InternalTimeServiceManager#advanceWatermark。测试时也可以手动改变isSkippedElement的值为true,简单mock 窗口没有late,也就是说isSkippedElement 反应的是当前窗口是否late,即窗口的清除时间(eventtime类型下:窗口中数据最大时间戳+allowedLateness)小于当前水位线。

加上 result.print();之后结果如下:


关于测输出(OutputTag)
OutputTag是一个带有名称及类型信息的side output标识;flink允许ProcessFunction、CoProcessFunction、ProcessWindowFunction、ProcessAllWindowFunction这些function输出side output,这些function的Context有一个output(OutputTag outputTag, X value)方法用于输出元素到side output
SingleOutputStreamOperator提供了getSideOutput方法,可以根据OutputTag来获取之前在function里输出的site output;WindowOperator的processElement方法在最后会判断,如果isSkippedElement为true而且isElementLate也为true,则在lateDataOutputTag不为null的情况下会将late的element输出到side output

demo如下:

~~~~.timeWindow(Time.milliseconds(10)).allowedLateness(Time.milliseconds(10)).
                sideOutputLateData(myTag)
                .process(new ProcessWindowFunction<Tuple2<String, Integer>, String, String, TimeWindow>(){
                    @Override
                    public void process(String s, Context context, Iterable<Tuple2<String, Integer>> elements, Collector<String> out) throws Exception {
                        for (Tuple2<String, Integer> element : elements) {
                           //忽略正常邏輯
                            //向outPutTag中輸出數據
                            context.output(myTag,element);
                        }
                    }
                });
        DataStream<Tuple2<String, Integer>> sideOutput = result.getSideOutput(myTag);

重点是 context.output(myTag,element);

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值