flink的state总结

1 无状态和有状态计算

        在讲flink state之前,必须先清楚flink无状态计算和有状态计算区别。

1.1 无状态计算

        观察每个独立的事件,并且会在最后一个时间出结果。比如一些报警和监控,一直观察每个事件,当触发警报的事件来临就会触发警告。

1.2 有状态计算

        有状态的计算就会基于多个事件来输出结果。

        有状态计算几种应用场景:

  • 去重:数据去重时候,需要了解哪些数据来过,哪些数据还没有来,已到的数据需要保存下来,保存的数据就是状态。
  • 窗口计算:窗口一分钟计算一次,在窗口触发前需要把这个窗口之内的数据先保留下来,窗口到达的时候,再将整个窗口内触发的数据输出。未触发的窗口内的数据也是一种状态。
  • 机器学习/深度学习:如训练的模型以及当前模型的参数也是一种状态,机器学习可能每次都用有一个数据集,需要在数据集上进行学习,对模型进行一个反馈。
  • 访问历史数据:比如与昨天的数据进行对比,需要访问一些历史数据。如果每次从外部去读,对资源的消耗可能比较大,所以也希望把这些历史数据也放入状态中做对比。

        有状态计算涉及中间状态的管理,下面引申出flink状态管理内容。

2 Flink状态管理

2.1 为什么需要状态管理

        管理状态最直接的方式就是将数据都放到内存中,但解决内存容量限制、7*24小野高可用,备份与恢复、横向扩展、恰好计算一次等场景问题,对状态管理提出了更高的要求。

2.2 理想的状态管理

  • 简单易用:提供了丰富的数据结构、多样的状态组织形式以及简洁的扩展接口,让状态管理更加易用
  • 稳定高效:实时作业一般需要更低的延迟,一旦出现故障,恢复速度也需要更快;当处理能力不够时,可以横向扩展,同时在处理备份时,不影响作业本身处理性能;
  • 自动可靠:Flink 提供了状态持久化,包括不丢不重的语义以及具备自动的容错能力,比如 HA,当节点挂掉后会自动拉起,不需要人工介入。

2.3 Flink状态分类

2.3.1 managed state

        managed state是有Flink Runtime管理的,状态可以自动存储、自动恢复的,可以在并行度发生变化时自动重新分配状态,并且还可以更好地进行内存管理。

        managed state分为两种:

  • operator state:一种基于Operate的,每个操作有状态的,每个操作之间不会相互影响。例如kafka connector,就使用了operator state
    • broadcast state也是operator state的一种,keyed state是operator state的特例
    • 又称为non-keyed state,每一个operator state都仅与一个operator的实例绑定
    • 常见的operator state是source state,例如记录当前source的offset
  • keyed state:一种基于key的,它永远和key绑定,key和key之间的state没有关系,不会相互影响
    • keyed state是operator state的特例,区别在于keyed state事先按照key对数据集进行了分区,每个keyed state仅对应一个Operator和Key的组合。
    • keyed state可以通过Key Groups进行管理,主要用于当算子并行度发生变化时,自动重新分布
    • 只能应用于 KeyedStream 的函数与操作中,例如 Keyed UDF, window statekeyed state
    • 是已经分区/划分好的,每一个 key 只能属于某一个 keyed state
  • operator state和keyed state比较
operator sateekeyed state
算子类型可用于所有的operator只能用户于keyed stream中的operator
状态分配单个operator对应一个state每个key对应一个state,单个operator可能多个keys
创建访问

实现CheckpointedFunction或

ListCheckpointed接口

重写RichFunction,通过RuntimeContext获取
横向扩展

多种状态重分配方式:

均匀分配

状态合并后再分发给每个实例

状态随着key自动在多个算子task上迁移
数据类型

支持的数据结构相对较少

ListState

UnionListState

BroadcastState

支持的数据结构相对较多

ValueState

MapState

ListState

ReducingState

AggregatingState

FoldingState

 2.3.2 raw state

        Raw State 需要用户自己管理,需要自己序列化,Flink 不知道 State 中存入的数据是什么结构,只有用户自己知道,需要最终序列化为可存储的数据结构。

2.3.3 managed state和raw state比较

Managed StateRaw State
管理方式Flink Runtime托管,自动存储、恢复、伸缩用户自行管理
数据结构

支持了一系列常见的数据结构

ValueState

ListState

MapState

……

只支持字节数组:byte[]
使用场景大部分Flink算子一般当Managed State不满足才使用

2.4 state有效期

        任何类型的 keyed state 都可以设置有效期 (TTL),如果配置了 TTL 且状态值已过期,则会尽最大可能清除对应的值。所有状态类型都支持单元素的TTL。 这意味着列表元素和映射元素将独立到期。在使用状态 TTL 前,需要先构建一个配置StateTtlConfig对象。 然后把配置传递到 state descriptor 中启用 TTL 功能。

2.4.1 TTL更新策略

  • OnCreateAndWrite:仅在创建和写入时更新(默认策略)
  • OnReadAndWrite:读取和写入时时更新

2.4.2 TTL过期数据可见性

  • NeverReturnExpired:过期数据不管是否被物理删除,都不返回过期数据(默认策略)
  • ReturnExpiredIfNotCleanedUp:过期数据,在数据被物理删除前都会返回

2.4.3 TTL过期数据清理策略

  • FULL_STATE_SCAN_SNAPSHOT :对过期状态不做主动清理,当执行完整快照(Snapshot / Checkpoint)时,会生成一个较小的状态文件,但本地状态并不会减小。唯有当作业重启并从上一个快照点恢复后,本地状态才会实际减小,因此可能仍然不能解决内存压力的问题。
  • INCREMENTAL_CLEANUP:对 Heap StateBackend生效,支持增量清理
  •  ROCKSDB_COMPACTION_FILTER:对 RocksDB StateBackend 有效,支持增量清理

2.5 state三种存储

  • MemoryStateBackend:将数据保存在java的堆里,默认异步方式快照
    • 限制
      • 单次状态大小最大默认被限制为5MB,这个值可以通过构造函数来更改
      • 无论单次状态大小最大被限制为多少,都不可用大过akka的frame大小
      • 聚合的状态都会写入JM的内存
    • 场景
      • 本地开发和调试
      • 状态比较少的作业
  • FsStateBackend :数据在TM的内存中,当做checkpointing的时候,会将状态快照写入文件,保存在文件系统或本地目录,少量的元信息会保存在JM的内存中,默认异步方式快照
    • 场景
      • 状态比较大,窗口比较长,大的KV状态
      • 需要做HA的场景
  • RocksDBStateBackend:保存数据在一个叫做RocksDB的数据库中,这个数据库保存在TM的数据目录中。当做checkpointing时,整个数据库会被写入文件系统和目录。少量的元信息会保存在JM的内存中,只支持异步快照。
    • 限制
      • 依赖于字节数组,支持的key和value的大小最大为2^31字节。对于使用Merge操作的状态,大小很可能就默默的超过了这个限制,下次获取就会失败
    • 场景
      • 非常大的状态,长窗口,大的KV状态
      • 目前唯一支持incremental的checkpoints的策略
      • 需要HA的场景

        其中 MemoryStateBackend、FsStateBackend 两种 StateBackend 在任务运行期间都会将 State 存储在内存中,两者在 Checkpoint 时将快照存储的位置不同。RocksDBStateBackend 在任务运行期间将 State 存储在本地的 RocksDB 数据库中。所以将 MemoryStateBackend、FsStateBackend 统称为 heap 模式,RocksDBStateBackend 称为 RocksDB 模式。

3 state使用总结

3.1 Heap 模式 ValueState 和 MapState 是如何存储的

        Heap 模式表示所有的状态数据都存储在 TM 的堆内存中,所有的状态都存储的原始对象,不会做序列化和反序列化。

        实质上 ValueState 中存 Map 与 MapState 都是一样的,存储结构都是CopyOnWriteStateMap<K, N, HashMap>,区别在于 ValueState 是用户手动创建 HashMap,MapState 是 Flink 引擎创建 HashMap。

  • ValueState :相当于用户手动创建了一个 HashMap 当做 V 放到了状态引擎中。
  • MapState 是:Flink 引擎帮用户创建了一个 HashMap 当做 V 放到了状态引擎中。

3.2 RocksDB 模式 ValueState 和 MapState 是如何存储的

        RocksDB 模式表示所有的状态数据存储在 TM 本地的 RocksDB 数据库中。RocksDB 是一个 KV 数据库,且所有的 key 和 value 都是 byte 数组。所以无论是 ValueState 还是 MapState,存储到 RocksDB 中都必须将对象序列化成二进制当前 kv 存储在 RocksDB 中。

  • ValueState :Flink 引擎会把整个Map 当做一个大 Value,存储在 RocksDB 中。对应到 RocksDB 中,100 个 KV 键值对的 Map 集合会序列化成一个 byte 数组当做 RocksDB 的 value,存储在 RocksDB 的 1 行数据中。
    • 每次修改操作需要序列化反序列化整个 Map 集合,每次序列化反序列大对象会非常耗 CPU,很容易将 CPU 打满。
  • MapState: 会根据 userKey,将 100 个 KV 键值对分别存储在 RocksDB 的 100 行中。
    • 每次修改操作只需要序列化反序列化 userKey 那一个 KV 键值对的数据,效率较高。

3.3 ValueState和MapState对比总结

  • Heap State 模式:ValueState和MapState存性能接近
  • RocksDB 模式:MapState比ValueState存Map性能高,数据量越大越明显
  • 建议尽量使用MapState,替换ValueState

        之前有个项目,广播白名单,对实时数据进行过滤。刚开始是用MemoryStateBackend存储广播数据,结构是ValueState,数据量小没有问题。后面白名单太大了,有几百M,切换成rocksdb存储,就有问题了。ValueState换成MapState,性能降下来了。

参考

Flink State 误用之痛,竟然 90% 以上的 Flink 开发都不懂 - 云+社区 - 腾讯云

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值