Flink和Kafka连接时的精确一次保证

Flink写入Kafka两阶段提交

端到端的 exactly-once(精准一次)

kafka -> Flink -> kafka

1)输入端

输入数据源端的 Kafka 可以对数据进行持久化保存,并可以重置偏移量(offset)

2)Flink内部

Flink 内部可以通过检查点机制保证状态和处理结果的 exactly-once 语义

3)输出端

两阶段提交(2PC)。

写入 Kafka 的过程实际上是一个两段式的提交:处理完毕得到结果,写入 Kafka 时是基于事务的"预提交";等到检查点保存完毕,才会提交事务进行"正式提交"。

如果中间出现故障,事务进行回滚,预提交就会被放弃;恢复状态之后,也只能恢复所有已经确认提交的操作。

必须的配置

1)必须启用检查点

2)指定 KafkaSink 的发送级别为 DeliveryGuarantee.EXACTLY_ONCE

3)配置 Kafka 读取数据的消费者的隔离级别【默认kafka消费者隔离级别是读未提交,2PC第一阶段预提交 数据也会被读到,下游消费者需要设置为读已提交】

4)事务超时配置

【配置的事务超时时间 transaction.timeout.ms 默认是1小时,而Kafka 集群配置的事务最大超时时间 transaction.max.timeout.ms 默认是15 分钟。在检查点保存时间很长时,有可能出现 Kafka 已经认为事务超时了,丢弃了预提交的数据;而Sink任务认为还可以继续等待。如果接下来检查点保存成功,发生故障后回滚到这个检查点的状态,这部分数据就被真正丢掉了。因此checkpoint 间隔 < 事务超时时间 < max的15分钟】

代码实战

kafka -> Flink -> kafka【Flink处理kafka来源数据再输出到kafka】

java 复制代码
public class KafkaEOSDemo {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        // 【1】、启用检查点,设置为精准一次
        env.enableCheckpointing(5000, CheckpointingMode.EXACTLY_ONCE);
        CheckpointConfig checkpointConfig = env.getCheckpointConfig();
        checkpointConfig.setCheckpointStorage("hdfs://hadoop102:8020/chk");
        checkpointConfig.setExternalizedCheckpointCleanup(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);

        // 2.读取 kafka
        KafkaSource<String> kafkaSource = KafkaSource.<String>builder()
                .setBootstrapServers("hadoop102:9092")
                .setGroupId("default")
                .setTopics("topic_1")
                .setValueOnlyDeserializer(new SimpleStringSchema())
                .setStartingOffsets(OffsetsInitializer.latest())
                .build();
        DataStreamSource<String> kafkasource = env
                .fromSource(kafkaSource,
                        WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(3)), "kafkasource");

        /*
         3.写出到 Kafka
          精准一次 写入 Kafka,需要满足以下条件,【缺一不可】
          1、开启 checkpoint
          2、sink 设置保证级别为 精准一次
          3、sink 设置事务前缀
          4、sink 设置事务超时时间: checkpoint 间隔 < 事务超时时间 < max的15分钟
         */
        KafkaSink<String> kafkaSink = KafkaSink.<String>builder()// 指定 kafka 的地址和端口
                .setBootstrapServers("hadoop102:9092")
                // 指定序列化器:指定 Topic 名称、具体的序列化
                .setRecordSerializer(
                        KafkaRecordSerializationSchema.<String>builder()
                                .setTopic("ws")
                                .setValueSerializationSchema(new SimpleStringSchema())
                                .build()
                )
                // 【3.1】 精准一次,开启 2pc
                .setDeliveryGuarantee(DeliveryGuarantee.EXACTLY_ONCE)

                // 【3.2】 精准一次,必须设置 事务的前缀
                .setTransactionalIdPrefix("li-")
                // 【3.3】 设置事务超时时间
                .setProperty(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG, 10 * 60 * 1000 + "")
                .build();
        kafkasource.sinkTo(kafkaSink);
        env.execute();
    }
}

后续读取"ws"这个 topic 的消费者 ,要设置事务的隔离级别为"读已提交"

java 复制代码
public class KafkaEOSConsumer {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        // 消费 在前面使用【两阶段提交】写入的 Topic
        KafkaSource<String> kafkaSource = KafkaSource.<String>builder()
                .setBootstrapServers("hadoop102:9092")
                .setGroupId("default")
                .setTopics("ws")
                .setValueOnlyDeserializer(new SimpleStringSchema()).setStartingOffsets(OffsetsInitializer.latest())
                // 作为 下游的消费者,要设置事务的隔离级别为 【读已提交】
                .setProperty(ConsumerConfig.ISOLATION_LEVEL_CONFIG, "read_committed")
                .build();
        env
                .fromSource(kafkaSource,
                        WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(3)), "kafkasource")
                .print();
        env.execute();
    }
}

处理程序以及消费程序如上设置才能真正实现端到端精准一次的保证。

相关推荐
starzy19909 小时前
Flink Akka底层原理深度剖析:从ActorSystem到Dispatcher调度器的底层实现
大数据·flink
ly768913 小时前
ISR 收缩与 HW 推进:副本同步的边界条件与 UnderReplicated 排障
数据库·kafka·c#·linq·isr·hw·副本同步
nvd1115 小时前
# 从 192 秒到 13 秒:Apache Flink 批处理极速调优实战记录
大数据·flink·apache
starzy19901 天前
Flink 优化之网络缓存优化及参数详解:从数据传输机制到反压原理的生产调优指南
网络·缓存·flink
此时不提桶,更待何时3 天前
06-09-A-Kafka架构与存储原理详解
架构·kafka·linq
智码看视界3 天前
Edge AI 全栈实战 ④:向量数据库 + RAG 让 IoT 诊断拥有“记忆“
flink·向量数据库·rag·全栈开发·edgeai·iot诊断
醉颜凉3 天前
Kafka 与 RabbitMQ/RocketMQ 选型对比:场景匹配、性能基准与迁移成本
kafka·消息队列·rabbitmq·rocketmq·中间件选型
筑梦之路3 天前
K8S yaml文件部署kafka集群(Kraft模式)——筑梦之路
容器·kafka·kubernetes
starzy19904 天前
Flink 优化之 CheckPoint 优化及参数详解:从原理到生产环境调优的完整指南
大数据·flink
筑梦之路4 天前
Kafka KRaft 模式 Kubernetes 部署手册(StatefulSet + apache/kafka 官方镜像)——筑梦之路
kafka·kubernetes·apache