flink的keyed state是有有效期(TTL)的,使用和说明在官网描述的篇幅也比较多,对于三种清理策略没有进行横向对比得很清晰。

  • 全量快照清理(FULL_STATE_SCAN_SNAPSHOT)
  • 增量清理(INCREMENTAL_CLEANUP)
  • rocksdb压缩清理(ROCKSDB_COMPACTION_FILTER)

如何停止flink 8081服务_大数据

注意,三种状态清理策略不是互斥的,并不是三选一的问题,一般是全量快照清理配合另两个其中的一个来使用(需要根据不同的state backend),可以看到StateTtlConfig.CleanupStrategies.strategies是一个集合来的。

全量快照清理

只发生在全量checkpoint的时候,把过期的元素过滤掉,以减少远程端checkpoint storage的大小(如hdfs),无论状态后端是hashmap还是rocksdb都支持,官网用了另一种相同意思描述:在 RocksDBStateBackend 的增量 checkpoint 模式下无效(当前hashmap不支持增量checkpoint)

  • 开启方式
StateTtlConfig ttlConfig = StateTtlConfig .newBuilder(Time.seconds(1))
        .cleanupFullSnapshot()   //只要有这行即可
        .build();
// 只有开启了全量快照清理才会触发transform(过滤)
    private StateSnapshotTransformFactory<?> getSnapshotTransformFactory() {
        if (!ttlConfig.getCleanupStrategies().inFullSnapshot()) {
            return StateSnapshotTransformFactory.noTransform();
        } else {
            return new TtlStateSnapshotTransformer.Factory<>(timeProvider, ttl);
        }
    }

当进行全量快照是会遍历状态中每个元素(TtlValue),过滤掉那些已经过期的StateSnapshotTransformer#filterOrTransform()该接口有几个实现类:

    1. TtlSerializedValueStateSnapshotTransformer:判断value是否过期,用于rocksdb状态后端
    2. TtlDerializedValueStateSnapshotTransformer:判断value是否过期,用于hashmap状态后端
    3. ListStateSnapshotTransformer:经1,2过期判断后的数据处理,对应hashmap后端的ListState
    4. MapStateSnapshotTransformer:经1,2过期判断后数据处理,对应hashmap后端的MapState
    5. RocksDBListState.StateSnapshotTransformerWrapper:经1,2过期判断后的数据处理,对应rocksdb后端的ListState
    6. RocksDBMapState.StateSnapshotTransformerWrapper:经1,2过期判断后的数据处理,对应rocksdb后端的MapState

    ps: rocksdb的MapState(第6个实现)中,当每个key的value过期后,返回的是一个byte[1]字节数组,3,4,5都对应返回了null,为什么??在使用时发现即使设置了ttl,但是过了每个ttl周期后,整个checkpoint size还是缓缓地持续增大,可能是依赖于rocksdb的compact把这些数据清理?

    当hashmap状态后端只使用了全量清理策略,在checkpoint界面看到的大小每次都都比较平均,但是堆内存却是持续增加的,所以要结合增量清理策略一起使用

    如何停止flink 8081服务_状态清理_02

    增量清理

    在状态访问、增加、修改、删除时都会触发,主要是为了减少状态后端中的大小,当前仅状态后端为hashmap才支持增量清理

    这里的增量有点难理解,实际它的含义是:对于一个keyed stated,状态是按key被分区成若干部分的,每次只取cleanupSize个key的状态(StateEntry)进行清理,对于大状态这是必须的,因为这会增加状态算子处理数据的时间。对于rocksdb,由于提供不了全局的StateEntry访问器,所以它不支持增量清理AbstractRocksDBState.getStateIncrementalVisitor

    判断是否满足增量清理:TtlStateFactory.registerTtlIncrementalCleanupCallback 清理逻辑:TtlIncrementalCleanup.runCleanup

    启用方式:这玩意在hashmap状态后端中是默认开启的!!!

    public IncrementalCleanupStrategy getIncrementalCleanupStrategy() {
                IncrementalCleanupStrategy defaultStrategy =
                        isCleanupInBackground ? DEFAULT_INCREMENTAL_CLEANUP_STRATEGY : null;
                return (IncrementalCleanupStrategy)
                        strategies.getOrDefault(Strategies.INCREMENTAL_CLEANUP, defaultStrategy);
            }

    只要isCleanupInBackground=true,就算没显式调用cleanupIncrementally(),它依然会给你生成一个默认的增量清理策略。所以在上述全量快照清理的启用示例中同时也开启了增量清理。如果需要禁止,需要显式调disableCleanupInBackground()

    rocksdb压缩清理

    flink 提供的 rocksdb 压缩过滤器(FlinkCompactionFilter)会在压缩时过滤掉已经过期的状态数据,最终调用到C++的nactive方法,减少sst文件的大小。应该与增量/全量checkpoint方式无关。

    压缩清理依赖于rocksdb自身的压缩策略,触发时间可能并不像增量清理那样实时,所以本地rocksdb会保留超过了TTL很长时间的过期数据(此时处于L1甚至L2),如果需要及时清理本地过期数据,则需要配置更"积极"的压缩策略。