Flink 检查点的持久化主要依赖于状态后端(State Backend),状态后端决定了检查点数据的存储位置和存储方式。 不同状态后端的持久化过程:
1. MemoryStateBackend
特点:这是 Flink 默认的状态后端,将状态数据和检查点数据存储在 TaskManager 的堆内存中,而检查点元数据存储在 JobManager 的堆内存中。它适合本地开发和测试,以及状态数据量较小的场景。
持久化过程
当触发检查点时,TaskManager 会将当前的状态数据收集起来,以内存对象的形式保存。
然后将这些状态数据的引用信息发送给 JobManager,JobManager 会将这些元数据存储在自己的堆内存中。
由于数据都存储在内存中,这种方式不适合大规模的状态数据,并且在 JobManager 或 TaskManager 出现故障时,可能会导致数据丢失。
MemoryStateBackend 示例
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.runtime.state.memory.MemoryStateBackend;
public class MemoryStateBackendExample {
public static void main(String[] args) throws Exception {
// 创建流执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 设置 MemoryStateBackend 作为状态后端
env.setStateBackend(new MemoryStateBackend());
// 启用检查点,间隔为 5000 毫秒(5 秒)
env.enableCheckpointing(5000);
// 示例:简单的 map 操作,假设输入是整数流,输出是整数的平方
env.fromElements(1, 2, 3, 4, 5)
.map(i -> i * i)
.print();
// 执行作业
env.execute("MemoryStateBackend Example");
}
}
MemoryStateBackend 会将状态数据和检查点元数据都存储在内存中,适用于本地测试或者状态数据量极小的简单场景。
2. FsStateBackend
特点:FsStateBackend 会将状态数据存储在 TaskManager 的本地磁盘上,而检查点数据会持久化到远程的文件系统(如 HDFS、S3 等)中。它适用于状态数据量较大,且需要高可靠性的场景。
持久化过程
状态数据存储:在正常的流处理过程中,算子的状态数据会存储在 TaskManager 的本地磁盘上,这样可以减少内存的使用压力。
检查点触发:当检查点协调器(JobManager)触发检查点时,TaskManager 会将本地磁盘上的状态数据复制到远程文件系统中指定的检查点目录下。
元数据存储:TaskManager 会将检查点的元数据(如状态数据的位置、检查点编号等)发送给 JobManager,JobManager 会将这些元数据存储在文件系统的检查点元数据文件中。
完成确认:当所有的 TaskManager 都完成状态数据的复制和元数据的发送后,JobManager 会标记该检查点为完成。
FsStateBackend 示例
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.runtime.state.filesystem.FsStateBackend;
public class FsStateBackendExample {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 设置 FsStateBackend 作为状态后端,指定 HDFS 路径存储检查点数据
env.setStateBackend(new FsStateBackend("hdfs://localhost:9000/flink/checkpoints"));
// 启用检查点,间隔为 5000 毫秒(5 秒)
env.enableCheckpointing(5000);
// 示例:简单的 filter 操作,假设输入是整数流,过滤出大于 2 的数
env.fromElements(1, 2, 3, 4, 5)
.filter(i -> i > 2)
.print();
// 执行作业
env.execute("FsStateBackend Example");
}
}
这里使用 FsStateBackend,将状态数据存储在 TaskManager 的本地磁盘,检查点数据存储到指定的 HDFS 路径下(hdfs://localhost:9000/flink/checkpoints),适合对可靠性有一定要求,且状态数据量适中的场景。
3. RocksDBStateBackend
RocksDBStateBackend 结合了本地 RocksDB 数据库和远程文件系统的优点。它将状态数据存储在本地的 RocksDB 数据库中,而检查点数据会持久化到远程文件系统中。RocksDB 是一种高性能的嵌入式键值存储数据库,适合处理大规模的状态数据。
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.contrib.streaming.state.RocksDBStateBackend;
public class RocksDBStateBackendExample {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 设置 RocksDBStateBackend 作为状态后端,指定 HDFS 路径存储检查点数据
env.setStateBackend(new RocksDBStateBackend("hdfs://localhost:9000/flink/checkpoints"));
// 启用检查点,间隔为 5000 毫秒(5 秒)
env.enableCheckpointing(5000);
// 示例:简单的 keyBy 和 sum 操作,假设输入是 Tuple2<Integer, Integer> 流,按第一个元素分组并对第二个元素求和
env.fromElements(
new Tuple2<>(1, 1),
new Tuple2<>(1, 2),
new Tuple2<>(2, 3)
)
.keyBy(t -> t.f0)
.sum(1)
.print();
// 执行作业
env.execute("RocksDBStateBackend Example");
}
// 定义 Tuple2 类(简化版)
public static class Tuple2<F0, F1> {
public F0 f0;
public F1 f1;
public Tuple2(F0 f0, F1 f1) {
this.f0 = f0;
this.f1 = f1;
}
}
}选择合适的状态后端
在选择状态后端时,需要综合考虑以下因素:
状态数据量:如果状态数据量较小,可以选择
MemoryStateBackend;如果状态数据量较大,则应选择FsStateBackend或RocksDBStateBackend。可靠性要求:对于对数据可靠性要求较高的场景,建议使用
FsStateBackend或RocksDBStateBackend,将检查点数据存储在远程文件系统中。性能要求:如果对检查点的时间和数据传输量有较高的要求,可以考虑使用支持增量检查点的
RocksDBStateBackend。
评论区