Keyed DataStream
键数据流(KeyedDataStream)概念:在flink中数据集为DataStream,对其进行分区时,会产生一个KeyedDataStream,然后允许使用键数据流的operator以及特有的state(如mapstate、valuestate等)
如果想使用key state,需要对DataStream指明一个key进行分区,也可以使用keyby创建一个KeyedDataStream,对这个KeyedDataStream可以使用keyed state。
keyby可以通过列下标选择使用列,也可以选择使用列名进行分区。由于flink的keyby不是key-value键值对形式,所以键是虚拟的。
使用Keyed State
keyed state有几种不同的类型,它们只能作用于KeyedStream,所以使用前,需要保证数据集为KeyedStream,比如先要调用stream.keyBy(…),相同的key都只有一个state共享使用。
将state用于程序中:
创建state必须要使用RuntimeContext进行访问,所以只能在RichFunction中才能创建和使用,例如:RichMapFunction、RichFlatMapFunction、RichFilterFunction和KeyedProcessFunction等。
- ValueState<T>:这个state只能保存一个值,可以对value state进行更新和提取,通过调用state.update(T)和state.value()完成,判断是否为空可以通过null == state.value()。
创建value state:
import org.apache.flink.api.common.state.{ValueState, ValueStateDescriptor}
val stateDescriptor = new ValueStateDescriptor[String]("value_state", createTypeInformation[String])
val value_state: ValueState[String] = getRuntimeContext.getState[String](stateDescriptor)
ListState<T>:这个state可以保存一个list集合的元素,可以进行添加和遍历一个
Iterable检索所有的元素。添加元素可以通过add(T)或者addAll(List<T>)进行单独和批量的添加,获取迭代器可通过state.get(),也可以通过update(List<T>)进行全部覆盖操作
创建list state:
import org.apache.flink.api.common.state.{ListStateDescriptor}
val listStateDescriptor = new ListStateDescriptor[String]("listStateDescriptor", createTypeInformation[String])
val list_state = getRuntimeContext.getListState[String](listStateDescriptor)
- ReducingState<T>:与
ListState相似,但这个state实际值保留一个值,当有新的元素加入时,会通过
ReduceFunction进行元素聚合 - AggregatingState<IN, OUT>:与ReducingState相似,也是对新元素与旧元素聚合后只保留一个值,但不同的是AggregatingState的输入与输出是不一样的数据类型
- MapState<key, value>:这是一个多元素的key-value形式state(使用方式类似于编程语言中的map)。使用put(key,value)或者putAll(Map<key, value>),检索使用get(key)。获取全部元素时,使用state.entries()、state.values()、state.values获取迭代器。还可以使用state.isEmpty()来判断是否是空的state。
创建一个key为string,value为List[JsonObject]形式的复合结构
import org.apache.flink.api.common.state.{MapState, MapStateDescriptor}
val ontimer_map_desc = new MapStateDescriptor[String, List[JsonObject]]("map_state", createTypeInformation[String], createTypeInformation[List[JsonObject]])
val map_state: MapState[String, List[JsonObject]] = getRuntimeContext.getMapState[String, List[JsonObject]](map_desc)
所有类型的state都可以通过state.clear清除所有元素。
state TTL(生存周期)
每个state都可以配置元素生存周期,当达到设定值时,会在后台清楚过期元素,保证state中都是有效数据。当前仅支持process time类型的TTL。
使用state TTL,需要创建一个StateTtlConfig配置对象,然后调用api进行自定义配置。
为state使用TTL示例
import org.apache.flink.api.common.state.StateTtlConfig
import org.apache.flink.api.common.state.ValueStateDescriptor
import org.apache.flink.api.common.time.Time
val ttlConfig =
StateTtlConfig.newBuilder(Time.minutes(10)) //生存时间值
.setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
.setStateVisibility(StateTtlConfig.StateVisibility.ReturnExpiredIfNotCleanedUp) //允许返回过期值
.cleanupFullSnapshot() // 在快照的时候进行删除
.cleanupInBackground() //在后台激活清理
.build()
val stateDescriptor = new ValueStateDescriptor[String]("text state", classOf[String])
stateDescriptor.enableTimeToLive(ttlConfig)
newBuilder是必须要有的,表示元素生存时间。
配置刷新TTL类型:
StateTtlConfig.UpdateType.OnCreateAndWrite
-仅在创建和写访问权限时(默认此配置)StateTtlConfig.UpdateType.OnReadAndWrite
- 在读取和写入时
配置过期元素是否可用,当外部调用已过期但没有被清除元素时执行此配置:
StateTtlConfig.StateVisibility.NeverReturnExpired
-永不返回过期值(默认此配置)StateTtlConfig.StateVisibility.ReturnExpiredIfNotCleanedUp
-如果仍然可用,没有被清除,则返回
清理过期状态:
- 完整快照时清理(cleanupFullSnapshot):在生成完整快照时执行清理操作,减轻大小
- 增量清理(cleanupIncrementaally):采取逐步触发清除策略,触发器拉矮子每次状态中元素的访问或者每个记录处理后的回调,如果不满足触发条件,会一直存在过期数据。
-
RocksDB压缩期间的清理(cleanupInRocksddbCompactFilter):当rockdb处理一定量的元素后,会检查到期时间,进行清除,会出现降低压缩性能的影响。