FLink-14-Flink 状态State的TTL管理
- Flink 状态State的TTL管理
- 1.updateTtlOnReadAndWrite()/updateTtlOnCreateAndWrite()
- 2.StateTtlConfig.StateVisibility.NeverReturnExpired/ReturnExpiredIfNotCleanedUp
- 3.cleanupStrategies(过期数据清理策略,目前支持的策略有)
- 嵌入式数据库相关整理
- HBase中的compact机制:major合并和minor合并
- Flink状态后端
- 1.Flink状态后端的定义:
- 2.Flink状态后端的分类
- 3.Flink状态后端和TTL的具体代码案例如下:
Flink 状态State的TTL管理
- flink 可以对状态数据进行存活时长管理,即"新陈代谢";
- 淘汰的机制主要是基于存活时间;
- 存活时长的计时器可以在数据被读、写时重置;
- Ttl 存活管理粒度是到元素级的(如 liststate 中的每个元素,mapstate 中的每个 entry),每条数据都有自己独立的TTL计时。
- 应用场景:
- 如果维度数据很大,量级很多,
- 可以将维度数据中热数据存放到State状态中,查询维度数据时,优先从state中查看,没有的话,再从基础架构中查询,这样就缩短了查询维度数据的时长;
- 同时,state中可以根据自定义需求设置TTL生命管理机制,为状态中数据设置失效时长以及失效策略。
1.updateTtlOnReadAndWrite()/updateTtlOnCreateAndWrite()
- updateTtlOnReadAndWrite() : ttl 重置刷新策略,数据只要被读取或者被写更新,则将它的 ttl 计时重置.
- updateTtlOnCreateAndWrite() : ttl 重置刷新策略,数据被创建及被写入更新,就将它的 ttl 计时重置
2.StateTtlConfig.StateVisibility.NeverReturnExpired/ReturnExpiredIfNotCleanedUp
- NeverReturnExpired(默认策略):状态数据的可见性:如果状态中存在还未清理掉的但是已经超出 ttl 的数据,不允许让用户程序可见,如下图所示
- ReturnExpiredIfNotCleanedUp:如果状态中存在还未清理掉的但是已经超出 ttl 的数据,可以允许让用户程序可见。
3.cleanupStrategies(过期数据清理策略,目前支持的策略有)
- cleanupIncrementally : 增量清除 每当访问状态时,都会驱动一次过期检查(算子注册了很多 key 的 state,一次检查只针对其中一部分: 由参数 cleanupSize 决定) 算子持有一个包含所有 key 的迭代器,每次检查后,迭代器都会向前 advance 指定的 key 数量; 本策略,针对“本地状态空间”,且只用于 HashMapStateBackend
- cleanupFullSnapshot 在进行全量快照(checkpoint)时,清理掉过期数据; 注意:只是在生成的 checkpoint 数据中不包含过期数据;在本地状态空间中,并没有做清理; 本策略,针对“快照”生效
- cleanupInRocksdbCompactFilter 只针对 rocksdbStateBackend 有效; 它是利用 rocksdb 的 compact 功能,在 rocksdb 进行 compact 时,清除掉过期数据; 本策略,针对“本地状态空间”,且只用于 EmbeddedRocksDbStateBackend
嵌入式数据库相关整理
- derby是一个数据库软件,任何软件都可以内嵌此数据库软件,它跟Mysql不同之处在于:
- mysql是一个独立的软件,是一个服务
- derby是一个嵌入式的数据库软件(工具包)
- derby是支持sql的关系型数据库
- rockdb就是一种嵌入式数据库 ,是kv数据库。
HBase中的compact机制:major合并和minor合并
Flink状态后端
1.Flink状态后端的定义:
- 所谓状态后端,就是状态数据的存储管理实现,包含状态数据的本地读写、快照远端存储功能;
- 状态后端是可插拔替换的,它对上层屏蔽了底层的差异,因为在更换状态后端时,用户的代码不 需要做任何更改。
2.Flink状态后端的分类
- Flink状态后端使用来存储Flink的State状态的,不管是valueState/listState/mapState/aggregateState/reduceingState都存储在状态后端里面,状态后端是放置在heap堆中,如果内存不够就会溢写到本地磁盘,状态后端有两种实现:
- HashMapStateBackend
- 默认使用此状态后端,状态数据就是存储在内存中,数据以对象的形式存在,内存不够溢写磁盘。
- RocksDbStateBackend
- 使用此状态后端,状态数据就不再是以java对象的形式存在,而是被序列化成字节存储。
- 存储超大规模的状态数据,用RocksDbStateBackend,综合效率更高。
- rocksDb中也有类似于HBase的compact的操作,在进行此操作的时候,可以将状态中的数据清理干净。
- 两种statebackend,生成的快照文件,格式是完全一致的。 这样做的目的:便于重启后,改变statebackend后,还能继续兼容重启前的上一种backend所生成的快照数据。
- 老版本(flink-1.12 版及以前) Fsstatebackend MemoryStatebackend RocksdbStateBackend
- 如需使用 rocksdb-backend,需要引入依赖以及代码中相关使用如下:
1.引入依赖
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-statebackend-rocksdb_2.12</artifactId>
<version>${flink.version}</version>
</dependency>
2.代码中设置参数:
/**
* 设置要使用的状态后端
*/
HashMapStateBackend hashMapStateBackend = new HashMapStateBackend();
env.setStateBackend(hashMapStateBackend);//使用HashMapStateBackend作为状态后端
EmbeddedRocksDBStateBackend embeddedRocksDBStateBackend = new EmbeddedRocksDBStateBackend();
env.setStateBackend(embeddedRocksDBStateBackend);//设置 EmbeddedRocksDBStateBackend 作为状态后端
3.Flink状态后端和TTL的具体代码案例如下:
package com.yang.flink.state;
import org.apache.flink.api.common.RuntimeExecutionMode;
import org.apache.flink.api.common.functions.AggregateFunction;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.api.common.functions.RichMapFunction;
import org.apache.flink.api.common.functions.RuntimeContext;
import org.apache.flink.api.common.restartstrategy.RestartStrategies;
import org.apache.flink.api.common.state.*;
import org.apache.flink.api.common.time.Time;
import org.apache.flink.api.common.typeinfo.TypeHint;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.contrib.streaming.state.EmbeddedRocksDBStateBackend;
import org.apache.flink.runtime.state.hashmap.HashMapStateBackend;
import org.apache.flink.streaming.api.CheckpointingMode;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* 键控状态使用演示
*/
public class TTLStateDemo {
public static void main(String[] args) {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
env.setRuntimeMode(RuntimeExecutionMode.STREAMING);
/**
* 设置要使用的状态后端
*/
HashMapStateBackend hashMapStateBackend = new HashMapStateBackend();
env.setStateBackend(hashMapStateBackend);//使用HashMapStateBackend作为状态后端
EmbeddedRocksDBStateBackend embeddedRocksDBStateBackend = new EmbeddedRocksDBStateBackend();
env.setStateBackend(embeddedRocksDBStateBackend);//设置 EmbeddedRocksDBStateBackend 作为状态后端
// 开启状态数据的checkpoint机制(快照的周期,快照的模式)
env.enableCheckpointing(1000, CheckpointingMode.EXACTLY_ONCE);
// 开启快照后,就需要指定快照数据的持久化存储位置
env.getCheckpointConfig().setCheckpointStorage("file:///d:/checkpoint/");
// 开启 task级别故障自动 failover
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(3,1000));
DataStreamSource<String> source = env.socketTextStream("localhost", 9999);
// 需要使用map算子来达到一个效果:
// 每来一条数据(字符串),输出 该条字符串拼接此前到达过的所有字符串
SingleOutputStreamOperator<String> mapOperator = source.keyBy(s -> s)
.map(new RichMapFunction<String, String>() {//使用map算子时候,键控状态算子,需要实现rich的function,获取到flink的状态
// 单值状态
ValueState<String> valueState;
// list状态
ListState<String> lstState;
// map状态
MapState<String, String> mapState;
@Override
public void open(Configuration parameters) throws Exception {
RuntimeContext runtimeContext = getRuntimeContext();
StateTtlConfig ttlConfig = StateTtlConfig.newBuilder(Time.seconds(5))//配置数据存活时长为5秒
// .updateTtlOnCreateAndWrite()//当插入和更新数据的时候,将该条数据的ttl计时重置
// .updateTtlOnReadAndWrite()//当读、写数据的时候,将该条数据的ttl计时重置
// .setStateVisibility(StateTtlConfig.StateVisibility.ReturnExpiredIfNotCleanedUp)//允许返回已过期但尚未被清理的数据
// .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)//不允许返回已过期但尚未被清理的数据
.setTtlTimeCharacteristic(StateTtlConfig.TtlTimeCharacteristic.ProcessingTime)//ttl计时的时间语义:设置为processTime
.useProcessingTime()//ttl计时的时间语义:设置为processTime
.cleanupIncrementally(1000,true)//增量清理(每当一条状态数据被访问,则会检查这条数据的ttl是否超时,是就删除)
.cleanupFullSnapshot()//全量快照清理策略(在checkpoint的时候,保存到快照文件中的只包含未过期的状态数据,但是它并不会清理算子本地的状态数据)
.cleanupInRocksdbCompactFilter(1000)//在rockdb的compact机制中添加过期数据过滤器,以在compact过程中清理掉过期状态数据
.build();
ValueStateDescriptor<String> vstate = new ValueStateDescriptor<>("vstate", String.class);
vstate.enableTimeToLive(ttlConfig);//开启TTL管理
ListStateDescriptor<String> lst = new ListStateDescriptor<>("lst", String.class);
lst.enableTimeToLive(ttlConfig);
// 获取一个 单值 结构的状态存储器
valueState = runtimeContext.getState(vstate);
// 获取一个List结构的状态存储器
lstState = runtimeContext.getListState(lst);
// 获取一个 Map 结构的状态存储器
mapState = runtimeContext.getMapState(new MapStateDescriptor<String, String>("xx", String.class, String.class));
}
@Override
public String map(String value) throws Exception {
lstState.add(value);
StringBuilder sb = new StringBuilder();
Iterable<String> iterable = lstState.get();
for (String s : iterable) {
sb.append(s);
}
return sb.toString();
}
});
mapOperator.print();
}
}