在flink中,state是其重要的特性之一。有了state使得在数据流上进行状态的计算成为了可能,为flink的发展做出了重要贡献。没有state时需要在flink上进行状态的计算将会非常复杂且在复杂场景下无法实现,如集群宕机时状态快照的保存。无论是使用flink和MySQL还是flink和其他的存储引擎都存在一些缺陷。既然state这么重要,不妨我们一起来学习、理解和使用state。
一、什么是state
在flink官方的定义中,将其定义为是一个能够在数据流上进行状态计算的框架。结合实际使用,state泛指在flink中有状态函数或运算符在对各个数据流的处理过程中存储的数据。注意:状态数据可以修改、查询,根据自己的业务场景,保存历史数据或者中间结果到状态(state)中。
state分为Keyed state和Operate state。Keyed state通常和key相关,仅可使用在KeyedStream的方法和算子中。Keyed state的初始化是在open函数中,读写操作一般定义在用户实现的算子函数中,例如RichMapFunction的map中。在checkpoint时,由flink自行备份当前state到checkpoint快照中,无需用户手动管理快照触发和生成的细节。而Operate state(non-keyed state),每个Operate state和一个并发实例进行绑定。Operate state需要用户实现CheckpointedFunction或ListCheckpointed,通过手动覆写接口中的函数来定义state的初始化和快照生成逻辑。
二、如何理解state
flink中的state分为有状态计算和无状态计算。在实际开发中,如何理解这两种计算的差异呢?下面我们通过其定义和举例的方式分别对其进行说明。
- flink中的有状态计算和无状态计算:
- 有状态计算:指新进入flink的数据流需要和历史的数据流进行相关的操作后,才能计算出正确的结果。
- 无状态计算:数据进入flink后,只需要对当前的数据流进行处理就能得到想要的正确的结果。
- 举例说明:
- 有状态计算,统计某一个单词出现的次数,随着输入流的不断输入,当某一个单词出现后,计数器加1,再次出现时,计数器加1后变为2,这类操作属于有状态计算操作,对新输入的数据流的操作总是会用到历史的数据流。
- 无状态计算,当输入流中yn的值是1时,对应输出“是”,yn的值是0或其他值时,对应输出“否”。这种对输入的数据流进行处理了就能得到相要的正确结果。一般情况下,无状态计算是一个幂等操作。
三、state中常用参数配置
配置项 | 配置值 | 释义说明 |
akka.ask.timeout | 60s | 设置超时时间 |
state_backend_rocksdb_ttl_ compaction_filter_enabled | true | 后台开启多线程压缩时清除 |
state_backend | rocksdb | 状态存储介质,flink提供了内存、文件系统和rocksdb三种存储介质。 |
state_backend_incremental | true | 增量设置checkpoint |
classloader_resolve_order | child-first | class解析顺序。默认情况下,flink会优先在child classloader(用户代码的classloader)中查找user-code classes,然后再在parent classloader(系统的classloader)中查找user-code classes。此机制可避免job与flink系统的版本冲突。 |
apus_slotmanager_slot_ placement_policy | SLOT | 槽,flink中计算资源的基本单位,TM的一个slot代表一个可用线程,该线程具有固定的内存,但CPU是共享的。一个槽在同一时间执行一个任务,TM拥有一个或多个槽。 |
apus.checkpoint.delete. recursive | false | 递归删除checkpoint |
taskmanager.memory. network.fraction | 0.25 | 网络缓存占flink总内存的比例 |
taskmanager.memory. network.min | 268435456 | 网络缓存的最小值 |
taskmanager.memory. network.max | 2147483648 | 网络缓存的最大值 |
taskmanager.network. request-backoff.max | 120000 | 下游输入请求上游输出的超时回退时间(单位:毫秒) |
state.backend.rocksdb.localdir | /export/io_tmp_dirs/rocksdb | 保存状态的rocksdb的文件路径 |
apus_cp_path_prefix | hdfs://[ns]/user/[user]/flink/cp | 设置CP(checkpoint)路径 |
apus_sp_path_prefix | hdfs://[ns]/user/[user]/flink/sp | 设置SP(savepoint)路径 |
以上表格中例举的参数仅为其中的一部分,在实际生产中,可根据集群的实际情况进行参数的增减,确保集群状态最优。
四、state应用场景
1、缓存场景
上文提到的计数器,每次都是基于已有的数在其上加1,这里对计数器里数据的存储即是其应用场景之一。再比如,多表关联时,由于每一表的数据流到达算子的时间有前后,可以把先到的数据流存储到state中,待其他的数据流到达后再把state的数据取出一起计算。
2、快照
流式任务上下线或宕机时,把停机时的数据流信息存储到state,便于集群恢复时从state获取停机时的数据流信息,便于精确恢复数据。