Flink MapState过期时间设置

一、业务背景

实时统计每天考勤人数

使用MapState<Srting, Set>

key:日期字符串 -> yyyyMMdd

value:当天考勤员工ID,利用Set自动去重的特性统计当前考勤人数

状态里只需要存储当天的数据,之前的数据可以清理掉。设置状态过期时间24小时,距离数据上一次修改超过24小时,该数据会被清理。

// 设置状态过期配置
StateTtlConfig ttlConfig = StateTtlConfig
        .newBuilder(Time.hours(24))
        .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
        .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
        .build();
MapStateDescriptor<String, Set> mapStateDescriptor = new MapStateDescriptor<>("MapStateDescriptor", String.class, Set.class);
// 状态过期配置与壮状态绑定
mapStateDescriptor.enableTimeToLive(ttlConfig);
attendanceUserIdState = getRuntimeContext().getMapState(mapStateDescriptor);

二、状态过期机制测试

每隔1秒发送一条数据,状态有效期设置为3秒。打印状态里的数据

public static void main(String[] args) throws Exception {
    StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

    DataStreamSource<String> stringDataStreamSource = env.addSource(new SourceFunction<String>() {
        @Override
        public void run(SourceContext<String> sourceContext) throws Exception {
            while (true) {
                TimeUnit.SECONDS.sleep(1);
                sourceContext.collect(LocalDateTime.now().toString());
            }
        }

        @Override
        public void cancel() {

        }
    });

    SingleOutputStreamOperator<Tuple2<String, Integer>> keyStream = stringDataStreamSource.map(new MapFunction<String, Tuple2<String, Integer>>() {
        @Override
        public Tuple2 map(String s) {
            return Tuple2.of(s, 1);
        }
    });

    KeyedStream<Tuple2<String, Integer>, Tuple> tuple2TupleKeyedStream = keyStream.keyBy(1);

    SingleOutputStreamOperator<String> map = tuple2TupleKeyedStream.map(new RichMapFunction<Tuple2<String, Integer>, String>() {
        transient MapState<String, Object> state;

        @Override
        public void open(Configuration parameters) throws Exception {
            StateTtlConfig ttlConfig = StateTtlConfig.newBuilder(Time.seconds(3))
                    .setUpdateType(StateTtlConfig.UpdateType.OnReadAndWrite)
                    .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
                    .build();

            MapStateDescriptor<String, Object> mapStateDescriptor = new MapStateDescriptor<>("mapStateDescriptor", String.class, Object.class);
            mapStateDescriptor.enableTimeToLive(ttlConfig);
            state = getRuntimeContext().getMapState(mapStateDescriptor);
        }

        @Override
        public String map(Tuple2<String, Integer> stringIntegerTuple2) throws Exception {
            state.put(stringIntegerTuple2.f0, new Object());
            Iterator<Map.Entry<String, Object>> iterator = state.iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> next = iterator.next();
                String key = next.getKey();
                System.out.println(key);
            }
            return "====================" + LocalDateTime.now();
        }
    });
    map.print();

    env.execute("StateDemo");
}

运行结果

2021-08-16T19:52:29.126
9> ====================2021-08-16T19:52:29.183
2021-08-16T19:52:29.126
2021-08-16T19:52:30.136
9> ====================2021-08-16T19:52:30.211
2021-08-16T19:52:29.126
2021-08-16T19:52:30.136
2021-08-16T19:52:31.141
9> ====================2021-08-16T19:52:31.242
2021-08-16T19:52:30.136
2021-08-16T19:52:31.141
2021-08-16T19:52:32.144
9> ====================2021-08-16T19:52:32.330
2021-08-16T19:52:31.141
2021-08-16T19:52:33.148
2021-08-16T19:52:32.144
9> ====================2021-08-16T19:52:33.355

三、知识点

报错:

Queryable state is currently not supported with TTL

检查UpdateType是否设置了Disabled。

状态中的过期数据如何被清理

默认情况下,只有在明确读出过期值时才会删除过期值,例如通过调用ValueState.value().

注意:这意味着默认情况下,如果未读取过期状态的数据,则不会删除它,可能会导致状态不断增长。

此外,还可以添加数据清理的策略,默认的和添加的策略都会生效。

1.cleanupFullSnapshot

在创建checkPoint或savepoint的完整快照时,不会包含状态中过期的数据。

该配置还是不会影响本地状态存储的大小,但是整个作业的完整快照会减少。只有当用户从快照重新加载到本地时,才会清除用户本地的状态。

StateTtlConfig ttlConfig = StateTtlConfig.newBuilder(Time.seconds(3))
        .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
        .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
        .cleanupFullSnapshot()
        .build();

2.cleanupIncrementally

只适用于对内存状态后端(FsStateBackend和MemoryStateBackend)。

在所有的状态上维护一个去全局的惰性迭代器。某些事件(例如状态访问)会触发清理。每次触发清理时,迭代器会向前遍历删除已过期数据。

StateTtlConfig ttlConfig = StateTtlConfig.newBuilder(Time.seconds(3))
        .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
        .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
        .cleanupIncrementally(10, false)
        .build();

参数1:每次触发清理时要检查的数据数量。

参数2:标志位,用于表示是否每条记录处理之后还出发清除逻辑。

3.cleanupInRocksdbCompactFilter

仅适用于RocksDB状态后端

RocksDB会定期运行一步的压缩流程来合并数据,该过滤器适用生存时间检查状态条目的过期时间戳,并丢弃所有的过期值。

StateTtlConfig ttlConfig = StateTtlConfig.newBuilder(Time.seconds(3))
        .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
        .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
        .cleanupInRocksdbCompactFilter(100L)
        .build();
posted @ 2021-08-16 23:00  yangyh11  阅读(2491)  评论(0编辑  收藏  举报