flink onTimer延迟数据处理

目录

 

场景:

onTimer 使用关键流程

数据处理流程

代码交互流程

onTimer 延迟数据处理的优劣

优点:

缺点:

onTimer 编码实践

业务场景描述

代码


场景:

某些特殊业务场景需要延迟数据处理,比如乱序数据。

某些业务场景只需要保留最新数据,中间更新过程忽略不计,比如客服问卷最新状态。

某些业务场景需要结合最近一段时间的数据进行处理,比如客服侧由于系统短时间单条数据更新多个字段,系统侧更新字段顺序错误,导致中间记录的 binlog 数据可能有误,需要结合一段时间的数据进行修正数据。

 

 

 

onTimer 使用关键流程

数据处理流程

  • key by 分区,把相同 key 的数据发送到同一个分区。
  • 单条数据会设置定时器,可以让单个分区里面多条数据的定时器时间一样,那就只触发一次定时器。

  • 单条数据可以更新 state,然后定时器触发时,可以再取 state 的数据进行业务逻辑处理。

 

代码交互流程

 

  • processElement 单条数据处理

  • onTimer 定时器回调

  • Managed State 缓存状态

  • TimerService 时间服务

 

 

onTimer 延迟数据处理的优劣

优点:

  • 利用自带的 state,丰富的数据结构 ValueState 存最新数据、ListState 最一段时间数据、MapState 存 kv 数据。

  • 下发数据灵活:定时器下发数据,每条数据都可以注册一个定时器下发一次数据,多条数据的定时器也可以合并成一个定时器下发一次数据。

  • 定时器触发时数据处理非常灵活:可以取到 state 里面的所有数据,然后根据业务的逻辑进行数据处理。

  • 下发数据量减少:比如2s延迟,多条数据合并成一个定时器,如果业务只要最新状态,就只需要下发一条数据。

 

 

缺点:

  • 数据会有一定延迟。

 

 

 

onTimer 编码实践

业务场景描述

客服问卷只要最新状态的情况,比如问卷评价的数据一定在问卷未评价的数据之后,有时候问卷已评价和未评价的数据时间相近,下游消费时会乱序,进而发生未评价的数据更新已评价的数据,数据库里面问卷最新状态就是未评价了。

通过 onTimer 延迟5s数据处理,把5s内的数据统一处理,然后只保留最新问卷下发,比如5s内有未评价和已评价两条数据,那就只下发一条已评价数据就行,下游消费就不会乱序了。

 

代码

1.按照问卷 id 进行 keyBy 分区。

        DataStream<String> npsMainStream = npsMainEntityDataStream
            .keyBy(new KeySelector<NpsMainEntity, String>() {
                @Override public String getKey(NpsMainEntity npsMainEntity) throws Exception {
                    String key = npsMainEntity.getId() + "";
                    return key;
                }
            }).process(new StateTimerForOutOrderDataFunction());

2.processElement 方法里面每条数据来更新 state,这里有两种情况:

  • ValueState 为空会被更新。

  • 已评价数据会更新 ValueState。

processElement 里面每条数据会注册一个定时器,ctx.timerService().registerProcessingTimeTimer(triggerTime);

3.onTimer 方法里面定时器触发,可以查询 state 进行业务逻辑处理

    /** 延迟下发数据,解决并发乱序问题 */
    static class StateTimerForOutOrderDataFunction extends KeyedProcessFunction<String, NpsMainEntity, String> {

        private final static int ttlMinute = 1000 * 5;
        private ValueState<NpsMainEntity> sendCacheStorage;

        @Override
        public void open(Configuration parameters) throws Exception {
            sendCacheStorage = getRuntimeContext().getState(new ValueStateDescriptor<NpsMainEntity>("CacheStorage", NpsMainEntity.class));
        }


        @Override public void processElement(NpsMainEntity npsMainEntity, Context ctx, Collector<String> out)
            throws Exception {
            try {
                // 每条 record 注册事件 ttlMinute 代表延迟时间
                /** 状态为空,或者状态是未评价,5s时间解决乱序问题 */
                if (sendCacheStorage.value() == null || sendCacheStorage.value().getEvaluationStatus() == 2
                    || npsMainEntity.getEvaluationCnt() == 1) {
                    sendCacheStorage.update(npsMainEntity);
                    writeSampleLog("update:" + npsMainEntity.toString(), NumberEnum.SEVEN);
                    // 合并定时器,秒级触发
                    long triggerTime = (System.currentTimeMillis() + ttlMinute) /1000 * 1000;
                    ctx.timerService().registerProcessingTimeTimer(triggerTime);
                }
                // 相关操作
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }
      
        // 到达时间点触发事件
        @Override public void onTimer(long timestamp, OnTimerContext ctx, Collector<String> out)
            throws Exception {
            String onTimerValue = JSON.toJSONString(sendCacheStorage.value());
            out.collect(onTimerValue);
            writeSampleLog("onTimer onTimerValue:" + onTimerValue, NumberEnum.ZERO);
        }

    }

 

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值