是一个Operator的运行的状态/历史值,是维护在内存中
数据流处理离不开状态管理,比如窗口聚合统计、去重、排序等
流程:
一个算子的子任务接收输入流,获取对应的状态,计算新的结果,然后把结果更新到状态里面
同个数据进到算子里面多少次,都是一样的输出,比如 filter
需要考虑历史状态,同个输入会有不同的输出,比如sum、reduce聚合操作
Flink管理,自动存储恢复
细分两类:
1.Keyed State 键控状态(用的多)
a.有KeyBy才用这个,仅限用在KeyStream中,每个key都有state ,是基于KeyedStream上的状态
b.一般是用richFlatFunction,或者其他richfunction里面,在open()声明周期里面进行初始化
c.ValueState、ListState、MapState等数据结构
2. Operator State 算子状态(用的少,部分source会用)
a.ListState、UnionListState、BroadcastState等数据结构
用户自己管理和维护
存储结构:二进制数组
状态值可能存在内存、磁盘、DB或者其他分布式存储中
ValueState 简单的存储一个值(ThreadLocal / String)
ValueState.value()
ValueState.update(T value)
ListState 列表
ListState.add(T value)
ListState.get() //得到一个Iterator
MapState 映射类型
MapState.get(key)
MapState.put(key, value)
官网链接:https://ci.apache.org/projects/flink/flink-docs-release-1.13/docs/ops/state/state_backends/
State状态后端:存储在哪里
Flink 内置了以下这些开箱即用的 state backends :
HashMapStateBackend、EmbeddedRocksDBStateBackend
如果没有其他配置,系统将使用 HashMapStateBackend。
MemoryStateBackend、FsStateBackend、RocksDBStateBackend
如果不设置,默认使用 MemoryStateBackend。
HashMapStateBackend 保存数据在内部作为Java堆的对象。
场景:
EmbeddedRocksDBStateBackend 在RocksDB数据库中保存状态数据
场景
旧版
配置
方式一:可以flink-conf.yaml使用配置键在 中配置默认状态后端state.backend。
可以配置的值是hashmap (HashMapStateBackend)、rocksdb (EmbeddedRocksDBStateBackend)
或实现状态后端工厂StateBackendFactory的类的完全限定类名
# The backend that will be used to store operator state checkpoints
state.backend: hashmap
# Optional, Flink will automatically default to JobManagerCheckpointStorage
# when no checkpoint directory is specified.
state.checkpoint-storage: jobmanager
state.backend: rocksdb
state.checkpoints.dir: file:///checkpoint-dir/
# Optional, Flink will automatically default to FileSystemCheckpointStorage
# when a checkpoint directory is specified.
state.checkpoint-storage: filesystem
方式二:代码 单独job配置例子
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStateBackend(new HashMapStateBackend());
env.getCheckpointConfig().setCheckpointStorage(new JobManagerCheckpointStorage());
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStateBackend(new EmbeddedRocksDBStateBackend());
env.getCheckpointConfig().setCheckpointStorage("file:///checkpoint-dir");
//或者
env.getCheckpointConfig().setCheckpointStorage(new FileSystemCheckpointStorage("file:///checkpoint-dir"));
注:使用 RocksDBStateBackend 需要加依赖
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-statebackend-rocksdb_${scala.version}</artifactId>
<version>1.13.1</version>
</dependency>
sum()、maxBy() 等函数底层源码也是有ValueState进行状态存储
需求:
根据订单进行分组,统计找出每个商品最大的订单成交额
不用maxBy实现,用ValueState实现
/**
* 使用valueState实现maxBy功能,统计分组内订单金额最高的订单
*
* @param args
*/
public static void main(String[] args) throws Exception {
//构建执行任务环境以及任务的启动的入口, 存储全局相关的参数
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
DataStream<String> ds = env.socketTextStream("127.0.0.1", 8888);
DataStream<Tuple3<String, String, Integer>> flatMapDS = ds.flatMap(new RichFlatMapFunction<String, Tuple3<String, String, Integer>>() {
@Override
public void flatMap(String value, Collector<Tuple3<String, String, Integer>> out) throws Exception {
String[] arr = value.split(",");
out.collect(Tuple3.of(arr[0], arr[1], Integer.parseInt(arr[2])));
}
});
//一定要key by后才可以使用键控状态ValueState
SingleOutputStreamOperator<Tuple2<String, Integer>> maxProductOrder = flatMapDS.keyBy(new KeySelector<Tuple3<String,String,Integer>, String>() {
@Override
public String getKey(Tuple3<String, String, Integer> value) throws Exception {
return value.f0;
}
}).map(new RichMapFunction<Tuple3<String, String, Integer>, Tuple2<String, Integer>>() {
private ValueState<Integer> valueState = null;
@Override
public void open(Configuration parameters) throws Exception {
valueState = getRuntimeContext().getState(new ValueStateDescriptor<Integer>("total", Integer.class));
}
@Override
public Tuple2<String, Integer> map(Tuple3<String, String, Integer> tuple3) throws Exception {
// 取出State中的最大值
Integer stateMaxValue = valueState.value();
Integer currentValue = tuple3.f2;
if (stateMaxValue == null || currentValue > stateMaxValue) {
//更新状态,把当前的作为新的最大值存到状态中
valueState.update(currentValue);
return Tuple2.of(tuple3.f0, currentValue);
} else {
//历史值更大
return Tuple2.of(tuple3.f0, stateMaxValue);
}
}
});
maxProductOrder.print();
env.execute("valueState job");
}
//全局配置checkpoints
state.checkpoints.dir: hdfs:///checkpoints/
//作业单独配置checkpoints
env.getCheckpointConfig().setCheckpointStorage("hdfs:///checkpoints-data/");
//全局配置savepoint
state.savepoints.dir: hdfs:///flink/savepoints
需要外部数据源可以重置读取位置,当发生故障的时候重置偏移量到故障之前的位置
依赖Checkpoints机制,在发生故障的时可以恢复各个环节的数据
当故障恢复时,数据不会重复写入外部系统,常见的就是 幂等和事务写入(和checkpoint配合)
//两个检查点之间间隔时间,默认是0,单位毫秒
env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);
//Checkpoint过程中出现错误,是否让整体任务都失败,默认值为0,表示不容忍任何Checkpoint失败
env.getCheckpointConfig().setTolerableCheckpointFailureNumber(5);
//Checkpoint是进行失败恢复,当一个 Flink 应用程序失败终止、人为取消等时,它的 Checkpoint 就会被清除
//可以配置不同策略进行操作
// DELETE_ON_CANCELLATION: 当作业取消时,Checkpoint 状态信息会被删除,因此取消任务后,不能从 Checkpoint 位置进行恢复任务
// RETAIN_ON_CANCELLATION(多): 当作业手动取消时,将会保留作业的 Checkpoint 状态信息,要手动清除该作业的 Checkpoint 状态信息
env.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
//Flink 默认提供 Extractly-Once 保证 State 的一致性,还提供了 Extractly-Once,At-Least-Once 两种模式,
// 设置checkpoint的模式为EXACTLY_ONCE,也是默认的,
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
//设置checkpoint的超时时间, 如果规定时间没完成则放弃,默认是10分钟
env.getCheckpointConfig().setCheckpointTimeout(60000);
//设置同一时刻有多少个checkpoint可以同时执行,默认为1就行,以避免占用太多正常数据处理资源
env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
//设置了重启策略, 作业在失败后能自动恢复,失败后最多重启3次,每次重启间隔10s
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(3, 10000));