state存储的数据
ValueState 会存储 key、namespace、value,缩写为 <K, N, V>。
MapState 会存储 key、namespace、userKey、userValue,缩写为 <K, N, UK, UV>。
下面解释这些名词
key
ValueState 和 MapState 都是 KeyedState,也就是 keyBy 后才能使用 ValueState 和 MapState。
所以 State 中肯定要保存 key。
group by uid。假设uid有id1、id2这两个值,id1、id2就是key。
Namespace
Namespace 用于区分窗口。
假设需要统计 app1 和 app2 每个小时的 pv 指标,则需要使用小时级别的窗口。
状态引擎为了区分 app1 在 7 点和 8 点的 pv 值,就必须新增一个维度用来标识窗口。
Flink 用 Namespace 来标识窗口,这样就可以在状态引擎中区分出 app1 在 7 点和 8 点的状态信息。
Value、UserKey、UserValue
ValueState 中存储具体的状态值。也就是上述例子中对应的 pv 值。
MapState 类似于 Map 集合,存储的是一个个 KV 键值对。
为了与 keyBy 的 key 进行区分,所以 Flink 中把 MapState 的 key、value 分别叫 UserKey、UserValue。
state的读写
Flink 支持三种 StateBackend,分别是:MemoryStateBackend、FsStateBackend 和 RocksDBStateBackend。
其中 MemoryStateBackend、FsStateBackend 两种 StateBackend 在任务运行期间都会将 State 存储在内存中,
两者在 Checkpoint 时将快照存储的位置不同。
RocksDBStateBackend 在任务运行期间将 State 存储在本地的 RocksDB 数据库中。
所以下文将 MemoryStateBackend、FsStateBackend 统称为 heap 模式,RocksDBStateBackend 称为 RocksDB 模式。
heap模式
Heap 模式表示所有的状态数据都存储在 TM 的堆内存中,所有的状态都存储的原始对象,不会做序列化和反序列化。
(注:Checkpoint 的时候会涉及到序列化和反序列化,数据的正常读写并不会涉及,所以这里先不讨论。)
Heap 模式下,无论是 ValueState 还是 MapState 都存储在 CopyOnWriteStateMap<K, N, V> 中。
- key 、 Namespace 分别对应 CopyOnWriteStateMap 的 K、N。
- ValueState 的 value 对应 CopyOnWriteStateMap 的 V。
MapState 将会把整个 Map 作为 CopyOnWriteStateMap 的 V,
相当于 Flink 引擎创建了一个 HashMap 用于存储 MapState 的 KV 键值对。
heap模式下,ValueState 中存 Map 与 MapState 有什么区别?
没有区别。实质上 ValueState 中存 Map 与 MapState 都是一样的,
存储结构都是 CopyOnWriteStateMap<K, N, HashMap>。
区别在于 ValueState 是用户手动创建 HashMap,MapState 是 Flink 引擎创建 HashMap。
RocksDB模式
RocksDB 模式表示所有的状态数据存储在 TM 本地的 RocksDB 数据库中。RocksDB 是一个 KV 数据库,且所有的 key 和 value 都是 byte 数组。
所以无论是 ValueState 还是 MapState,存储到 RocksDB 中都必须将对象序列化成二进制当前 kv 存储在 RocksDB 中。
在rocksdb中,每次state的度操作,都需要反序列化key、value;每次state写操作,都需要序列化key、value。
而heap模式是不需要序列化的,就这来说heap模式具有更高的性能。
ValueState的存储
ValueState 有 key、namespace、value 需要存储
- 将 ValueState 的 key 序列化成 byte 数组
- 将 ValueState 的 namespace 序列化成 byte 数组
- 将两个 byte 数组拼接起来做为 RocksDB 的 key
- 将 ValueState 的 value 序列化成 byte 数组做为 RocksDB 的 value
MapState的存储
MapState 有 key、namespace、userKey、userValue 需要存储,所以最简单的思路:
- 将 MapState 的 key 序列化成 byte
- 将 MapState 的 namespace 序列化成 byte
- 将 MapState 的 userKey 序列化成 byte
- 将三个 byte 数组拼接起来做为 RocksDB 的
- 将 MapState 的 value 序列化成 byte 数组做为 RocksDB 的 value
mapState不是保存整个map,而是map中的每个元素都单独保存到rocksdb中。
RocksDB 模式下,ValueState 中存 Map 与 MapState 有什么区别?
ValueState 中存 Map,Flink 引擎会把整个 Map 当做一个大 Value,存储在 RocksDB 的 1 行数据中。
MapState 会根据 userKey,将 100 个 KV 键值对分别存储在 RocksDB 的 100 行中。
ValueState中的map,每次读写都需要序列化整个map,这会极大的降低性能(非常耗 CPU)。
udaf和state
自定义聚合函数都被封装成了:GroupAggProcessFunction,,执行processElement
override def processElement(
inputC: CRow,
ctx: KeyedProcessFunction[K, CRow, CRow]#Context,
out: Collector[CRow]): Unit = {