Flink 是一个分布式流处理框架,能够支持精确一次(Exactly-Once)的状态一致性保证。为了实现这种精确一次的语义,Flink 采用了 Checkpointing 机制来保存应用程序的状态。本文将详细介绍 Flink Checkpoint 的相关参数。
Checkpoint 是指在运行 Flink 应用程序时,周期性地将应用程序的状态进行快照,并将这个状态保存到持久化存储设备中。如果应用程序发生故障,Flink 可以从最近的 Checkpoint 中恢复应用程序状态,使得应用程序能够继续执行而不会出现任何数据丢失的情况。
在 Flink 中,Checkpoint 有以下几个关键参数:
- checkpointing.mode
这个参数定义了应用程序使用的 Checkpoint 模式。默认值是 EXACTLY_ONCE,也就是精确一次模式。还可以选择 AT_LEAST_ONCE 模式或者 DISABLED 关闭 Checkpoint。
- checkpointing.interval
这个参数定义了两个 Checkpoint 之间的时间间隔。通常情况下,Checkpoint 时间间隔需要根据应用程序的特点进行调整。如果 Checkpoint 时间间隔过长,那么应用程序需要容忍更多的数据丢失风险;如果 Checkpoint 时间间隔过短,那么会增加 Checkpoint 的负担和延迟。
- checkpointing.timeout
这个参数定义了 Checkpoint 的超时时间。如果一个 Checkpoint 操作在这个时间内没有完成,那么 Flink 将会放弃当前的 Checkpoint 并继续进行下一个 Checkpoint 操作。
- checkpointing.min-pause
这个参数定义了两次 Checkpoint 之间最小的时间间隔。如果上一个 Checkpoint 操作还没有完成,那么 Flink 将会等待一段时间才会启动下一个 Checkpoint 操作。
- checkpointing.max-concurrent-checkpoints
这个参数定义了同时进行的最大 Checkpoint 数量。如果当前正在进行的 Checkpoint 数量已经达到了这个阈值,那么 Flink 将不会启动新的 Checkpoint 操作。
- checkpointing.checkpoint-idle-timeout
这个参数定义了当应用程序处于空闲状态时,自动触发的 Checkpoint 时间。如果应用程序在这个时间内没有任何输入数据,那么 Flink 将会自动触发一个 Checkpoint。
- state.backend
这个参数定义了应用程序使用的状态后端类型。Flink 支持多种不同类型的状态后端,包括 MemoryStateBackend、FileSystemStateBackend 和 RocksDBStateBackend 等。不同的状态后端有着各自的优缺点,需要根据实际情况进行选择。
- state.checkpoints.dir
这个参数定义了 Checkpoint 数据保存的位置。通常情况下,建议将 Checkpoint 数据保存到分布式文件系统中,比如 HDFS 或者 S3 等。
除了上述参数之外,Flink 还支持对 Checkpoint 进行更加细粒度的配置。比如可以设置是否在进行 Checkpoint 时暂停任务执行,或者设置是否在进行 Checkpoint 时取消正在等待的任务等。通过合理的配置,能够进一步提升 Flink 应用程序的性能和可靠性。 除此之外Checkpoint 有多种类型,包括全局 checkpoint、自定义 checkpoint 和 local checkpoint。下面详细介绍 Flink 的 Checkpoint 参数。
- 全局 checkpoint 全局 checkpoint 是 Flink 集群中最常用的一种 checkpoint 类型。它可以让 Flink 集群自动化地重启失败的任务,而不需要手动执行 stop-all 命令。 全局 checkpoint 有以下参数:
-
checkpoint.period.bytes:指定全局 checkpoint 的时间间隔,单位为字节。
-
checkpoint.strategy:指定全局 checkpoint 的触发方式,有三种常用的方式:
- 时间点触发:在每个时间点上进行全局 checkpoint。
- 流量触发:在 Flink 集群中的吞吐量达到一定阈值时进行全局 checkpoint。
- 系统事件触发:由 Flink 系统事件触发,如检测到任务异常等。
-
savepoint.path:指定保存全局 checkpoint 的路径,如 Hdfs、Distributed Cache 等。
- 自定义 checkpoint 自定义 checkpoint 可以让用户指定自己想要的 checkpoint 方式。 自定义 checkpoint 有以下参数:
- checkpoint.period.bytes:指定自定义 checkpoint 的时间间隔,单位为字节。
- checkpoint.strategy:指定自定义 checkpoint 的触发方式,与全局 checkpoint 的触发方式相同。
- savepoint.path:指定保存自定义 checkpoint 的路径,与全局 checkpoint 的保存路径相同。
- local checkpoint
local checkpoint 是 Flink 集群中的一种特殊的 checkpoint,只能由任务自己触发。当任务失败时,可以通过调用
WorkerStateStore.saveLocalCheckpoint()方法来创建 local checkpoint,任务继续执行时可以通过调用WorkerStateStore.loadLocalCheckpoint()方法来读取 local checkpoint。 local checkpoint 有以下参数:
-
local-dir:指定本地 checkpoint 的保存路径。 下面是一个简单的示例代码,展示了如何使用 Checkpoint 进行自定义的 Checkpoint 创建和使用:
public class MyCheckpointExample { public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.setParallelism(1); env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime); // 自定义 Checkpoint 创建方式 long checkpointPeriodMs = 30000L; // checkpoint 时间间隔为 3 分钟 String checkpointDir = "/path/to/checkpoint"; // 保存路径 CheckpointOptions checkpointOptions = CheckpointOptions.newBuilder() .setCheckpointPeriodMs(checkpointPeriodMs) .build(); env.setCheckpointOptions(checkpointOptions); // 创建任务并启动 DataStream<String> stream = env .addSource(new FlinkKafkaConsumer<>("topic", new SimpleStringSchema(), props)) .map(new MyMapper()) .setCheckpointConfig(new MyCheckpointConfig()) .setParallelism(1) .setMaxParallelism(1) .start(); // 在任务失败时创建 local checkpoint DataStream<String> localCheckpoint = stream .map(new MyCheckpointMapper()) .keyBy("id") .sum(1); // 只保留一条记录,用于计算自定义的 local checkpoint // 停止任务 env.execute("STOP"); // 读取 local checkpoint DataStream<String> finalCheckpoint = localCheckpoint .keyBy("id") .map(new MyCheckpointMapper()) .keyBy("checkpointId") .sum(1); // 输出结果 finalCheckpoint.print();}
public static class MyMapper extends RichMapper { private MyCheckpointMapper() { // 禁止使用构造方法 } }
public static class MyCheckpointMapper extends RichMapper { private MyCheckpointMapper() { // 禁止使用构造方法 }
@Override public void open(Configuration parameters) throws Exception { // 读取自定义的 local checkpoint LocalCheckpointStateHandle handle = LocalCheckpointStateHandle.loadLocalCheckpointStateHandle( new Path(checkpointDir), parameters.getLong(CHECKPOINT_PERIOD_MS, 30000L)); DataStream<String> localCheckpointStream = getRuntimeContext().getCheckpointDataManager() .getLocalCheckpointStream(handle); localCheckpointStream.print(); }}
public static class MyCheckpointConfig implements CheckpointOptions { private long checkpointPeriodMs;
public MyCheckpointConfig() { this(30000L); } public MyCheckpointConfig(long checkpointPeriodMs) { this.checkpointPeriodMs = checkpointPeriodMs; } @Override public String getKey() { return "MyCheckpointConfig"; } @Override public String getAlgorithm() { return "my-algorithm"; } @Override public void write(File directory) throws IOException { Files.createDirectories(directory.toPath()); Files.write(directory.toPath(), " " + checkpointPeriodMs + "ms"); } @Override public CheckpointPeriod getCheckpointPeriod() { return CheckpointPeriod.of(checkpointPeriodMs, TimeUnit.MILLISECONDS); }}
public static class MyCheckpointMeterStateHandle extends MetricUpdaterStateHandle { private MyCheckpointMeterStateHandle(String statePath) { super(statePath); }
public static MyCheckpointMeterStateHandle of(String statePath) { return new MyCheckpointMeterStateHandle(statePath); }}
public static class MyCheckpointMeterStateHandle extends StateHandleFetcher { private MyCheckpointMeterStateHandle(String statePath) { super(statePath); }
public static MyCheckpointMeterStateHandle of(String statePath) { return new MyCheckpointMeterStateHandle(statePath); }}
}