1.checkpoint介绍
Checkpoint,就是流式程序中用来做容错的机制。
它是通过JobManager的检查点协调器(checkpoint coordinator)来协调工作的。
2.checkpoint的执行流程
执行流程参考如下:
(1)checkpoint coordinator(检查点协调器)会周期性发送一个个的barrier(栅栏),这个barrier会随着数据流,流向source算子
(2)算子在处理时,如果发现是barrier(栅栏),那么这个算子就会停下手里的工作,把状态向checkpoint coordinator进行状态的汇报
(3)在状态汇报完之后,barrier就会随着数据流继续往下游传递
(4)下游的算子在碰到barrier后,会重复上面的流程
(5)以此类推,直到所有算子的状态都汇报完成,这一轮的checkpoint(快照)就做完了
(6)如果中间出现状态汇报失败等各种情况,说明这一轮的checkpoint制作失败。会等待下一轮的checkpoint快照制作。
3.Restart Strategy(重启策略)
Flink的重启策略有四种,分别是:
- noRestart(不重启)
- fixedDelayRestart(固定延迟重启)
- failureRateRestart(失败率重启)
- exponentialDelayRestart(指数延迟重启)
不重启
如果程序出错了,那就停止。
如果checkpoint关闭,那么默认就是不重启策略。
配置如下:
#1.配置文件中的写法
restart-strategy.type: none
#2.Java代码配置
env.setRestartStrategy(RestartStrategies.noRestart());
固定延迟重启
运行流式程序固定能够重启的次数。比如5次。
如果checkpoint开启,默认的重启的次数就是整形的最大值。(Integer.MAX_VALUE)
代码中配置如下:
#1.Java代码
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(
3, // 重启的次数
Time.of(10, TimeUnit.SECONDS) // 每一次重启的间隔时间
));
#2.配置文件中的写法
restart-strategy.fixed-delay.attempts: 3
restart-strategy.fixed-delay.delay: 10 s
#1.上面两种的含义如下
每隔10秒钟任务重启,总的重启次数为3次。
失败率重启
在一定的时间范围内,运行任务失败的频率。比如:1分钟允许失败3次。
代码配置如下:
#1.配置文件中的写法
restart-strategy.type: failure-rate
restart-strategy.failure-rate.max-failures-per-interval: 3
restart-strategy.failure-rate.failure-rate-interval: 5 min
restart-strategy.failure-rate.delay: 10 s
#2.Java代码的写法
env.setRestartStrategy(RestartStrategies.failureRateRestart(
3, // 最大的重启次数
Time.of(5, TimeUnit.MINUTES), //在五分钟内
Time.of(10, TimeUnit.SECONDS) // 每一次重启的间隔时间
));
#3.上面两个配置含义如下
在5分钟之内,最多允许重启3次。
指数延迟重启
每一次的重启会随着指数的递增而递增。
配置参考如下:
#1.配置文件中的写法
restart-strategy.type: exponential-delay
restart-strategy.exponential-delay.initial-backoff: 10 s
restart-strategy.exponential-delay.max-backoff: 2 min
restart-strategy.exponential-delay.backoff-multiplier: 2.0
restart-strategy.exponential-delay.reset-backoff-threshold: 10 min
restart-strategy.exponential-delay.jitter-factor: 0.1
#2.Java代码的写法
env.setRestartStrategy(RestartStrategies.exponentialDelayRestart(
Time.milliseconds(1),
Time.milliseconds(1000),
1.1, // exponential multiplier
Time.milliseconds(2000), // threshold duration to reset delay to its initial value
0.1 // jitter
));
#3.上面两个配置的含义如下
任务初始的重启时间为1毫秒,最大的重启时间为1秒钟,指数为1.1
如果任务稳定运行超过2秒,那么重启时间会重置为初始值(1毫秒)
抖动因子,是为了防止大量的任务在同一时刻重启。
重启策略小结
工作中,一般使用固定延迟重启或者失败率重启。
4.StateBackend(状态后端)
状态后端,就是专门用来保存checkpoint coordinator(检查点协调器)快照数据的。
默认情况下,它保存在JobManager的内存里。很显然,这种方式不太好。
Flink提供了3种状态后端的保存方式:
- memoryStateBackend(内存状态后端)
- FsStateBackend(文件系统状态后端)
- RocksDBStateBackend(RocksDB数据库状态后端)
memoryStateBackend
统一全局快照数据保存在JobManager的内存中。这种方式几乎不用。
从节点算子的状态保存在TaskManager的内存中。
配置参考如下:
#1.配置文件中
state.backend: hashmap
state.checkpoint-storage: jobmanager
#2.Java代码中
env.setStateBackend(new HashMapStateBackend());
env.getCheckpointConfig().setCheckpointStorage(new JobManagerCheckpointStorage());
FsStateBackend
统一全局快照数据保存在文件系统中,比如:HDFS。
从节点算子的状态保存在TaskManager的内存中。
整体比较安全,这也是推荐的状态后端保存方式。
配置参考如下:
#1.配置文件中
state.backend: hashmap
state.checkpoints.dir: file:///checkpoint-dir/
state.checkpoint-storage: filesystem
#2.Java代码中
env.setStateBackend(new HashMapStateBackend());
env.getCheckpointConfig().setCheckpointStorage("file:///checkpoint-dir");
env.getCheckpointConfig().setCheckpointStorage(new FileSystemCheckpointStorage("file:///checkpoint-dir"));
RocksDBStateBackend
这是一种可以保存超大状态的状态后端,也是唯一一个可以支持增量状态的保存的状态后端,一般用的不多。
RocksDB:是一个本地的数据库。这个数据库就在TaskManager。
如果是用RocksDBStateBackend,Java代码中必须添加RocksDB的依赖:
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-statebackend-rocksdb</artifactId>
<version>1.15.4</version>
<scope>provided</scope>
</dependency>
配置参考如下:
#1.配置文件中
state.backend: rocksdb
state.checkpoints.dir: file:///checkpoint-dir/
state.checkpoint-storage: filesystem
#2.Java代码中,注意:必须添加rocksdb的pom依赖才行
env.setStateBackend(new EmbeddedRocksDBStateBackend());
env.getCheckpointConfig().setCheckpointStorage("file:///checkpoint-dir");
env.getCheckpointConfig().setCheckpointStorage(new FileSystemCheckpointStorage("file:///checkpoint-dir"));
小结
在公司中,一般使用FsStateBackend就够了。
综合案例
package day07;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.restartstrategy.RestartStrategies;
import org.apache.flink.api.java.tuple.Tuple2;
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.CheckpointConfig;
import org.apache.flink.streaming.api.environment.ExecutionCheckpointingOptions;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
/**
* @author: itcast
* @date: 2023/4/13 21:00
* @desc: 需求:演示checkpoint机制
*/
public class Demo01_CheckpointDemo {
public static void main(String[] args) throws Exception {
//1.构建流式执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
//开启checkpoint,并设置为1秒钟
env.enableCheckpointing(1000);
// 额外配置信息,最后配置
// 设置为精准一次语义,默认就是Exactly_once
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
// 设置两次checkpoint的间隔最小为500毫秒
env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);
// 设置超时时间
env.getCheckpointConfig().setCheckpointTimeout(60000);
// 设置同时只能有1个checkpoint正在运行
env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
//任务取消后,checkpoint目录是否保存,这里配置的是保存
env.getCheckpointConfig().setExternalizedCheckpointCleanup(
CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
//配置checkpoint的存储路径
env.getCheckpointConfig().setCheckpointStorage("file:///d:\\checkpoint");
//设置重启策略为固定延迟重启
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(3,1000));
//2.数据源
DataStreamSource<String> source = env.socketTextStream("node1", 9999);
//3.数据处理
SingleOutputStreamOperator<Tuple2<String, Integer>> mapData = source.map(new MapFunction<String, Tuple2<String, Integer>>() {
@Override
public Tuple2<String, Integer> map(String value) throws Exception {
if ("aaa".equals(value)) {
throw new Exception("敏感词来了,程序挂了……");
}
return Tuple2.of(value, 1);
}
});
SingleOutputStreamOperator<Tuple2<String, Integer>> result = mapData.keyBy(value -> value.f0)
.sum(1);
//4.数据输出
result.print();
//5.启动流式任务
env.execute();
}
}