Kafka 原子更新,精确一次消费 Exactly-Once --------- 学习笔记

目录

原子更新

精确一次消费

写入幂等

事务消息

总结


原子更新

Kafka 如何实现原子更新?即操作要么完全成功、要么完全失败,无中间状态。核心结论是:Kafka 本身不直接提供 "更新" 语义,但可通过原子写入 + 消费语义 + 外部协调实现业务层面的原子更新。

Kafka 的生产者写入是原子性的,一条消息要么持久化成功,要么失败。支持消息生产者写入幂等和事务消息,保证消息 "仅一次交付",避免重复写入。Kafka 消费者手动提交位移 offset 是原子提交,原子更新,确保消费状态不丢失、不重复。

方案:

生产端:Producer 中要么消息必须带 key,让同类型业务消息绑定到指定的分区;或是由 Key + 分区器共同决定;或是使用事务消息。

消费端:简单场景消费者手动 commitSync(业务层使用唯一 id 或是 使用版本号)。复杂场景消费也需要用到"事务型消费",把消费操作放在一个数据库事务里,保存 offset 到数据库,执行完消费操作再手动提交 offset 到 Brocker。消费业务层面必须做幂等。

精确一次消费

在分布式场景下,消息传递通常会面临三种语义:

At-Most-Once(最多一次):消息可能丢失, but 不会重复消费,适用于非核心场景(如日志采集);

At-Least-Once(至少一次):消息不会丢失, but 可能重复消费,是Kafka默认的语义,可以结合消息id 和 Redis 过滤解决重复消费问题;

Exactly-Once(精确一次):消息既不丢失,也不重复消费,是金融、订单等核心业务的刚需。

其中:幂等性仅保证单生产者单分区的 "仅一次写入",事务消息可实现跨分区 / 跨主题的原子写入;

写入幂等

因为 Kafka 生产者启动时会从 Broker 获取到一个 PID,它发送消息时会根据 路由键 key 路由到某个主题下的某一个分区。写入时从分区中获得下一个 Sequence Number 序列号,然后分区写入时比对 pid,seq 是否已存在,已存在 seq 就是重复消息,丢弃,如果发现 seq 就是最新消息位置 pos+1,那就写入;所以开启 enable.idempotence = true 幂等特性,幂等性保证单生产者单分区的 "仅一次写入"。

事务消息

Kafka 事务消息依赖Transaction Coordinator(事务协调器)和Transaction Log(事务日志)来实现,事务协调器负责管理事务的生命周期(开始、提交、回滚),事务日志负责持久化存储,避免宕机丢失。

Producer 启动事务前会和 Transaction Coordinator 建立连接,然后 Producer 生产者调用 beginTransaction()方法,向事务协调器发送"启动事务"请求; 事务协调器生成唯一的 Transaction ID(事务ID),并将事务状态标记为"BEGIN",记录到事务日志。

Producer 向多个 Partition 发送消息(可跨 Partition),发送时携带 Transaction ID 和 PID;Broker 接收消息后,不会立即将消息置为"可消费"状态,而是标记为"事务未提交",暂时隐藏,Consumer 无法拉取 。

Producer确认所有消息都已成功发送到Broker(收到所有ack),调用commitTransaction()方法,向Transaction Coordinator发送"提交事务"请求;Transaction Coordinator收到请求后,先检查该事务下的所有消息是否都已成功持久化;若全部持久化成功,将事务状态标记为"COMMITTED",并向所有相关Broker发送"提交确认";Broker收到确认后,将"事务未提交"的消息置为"可消费"状态,Consumer可正常拉取消费。

若发送过程中出现异常(如部分消息发送失败、Producer宕机),Producer调用abortTransaction()方法,向Transaction Coordinator发送"回滚事务"请求;

Transaction Coordinator将事务状态标记为"ABORTED",并向所有相关Broker发送"回滚确认";

Broker收到确认后,删除"事务未提交"的消息,不会让Consumer拉取,实现事务回滚。

总结

1,开启幂等性,enable.idempotence = true。

2,启用事务消息,配置 transactional.id=xxx ,全局唯一,建议和 Producer 实例绑定;同时开启幂等性;设置 isolation.level=read_committed ,只消费已提交的事务消息,避免消费未提交的消息;

3,消息确认机制,设置 acks=all(所有副本确认),确保消息真正持久化,避免 Broker宕机导致消息丢失;

相关推荐
一隅论数智3 天前
给AI一张“业务概念地图“:本体如何从哲学走向企业智能
大数据·人工智能·经验分享·笔记·学习·学习方法·政务
XiHongShi20163 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
爱吃苹果的日记本3 天前
离散数学第六课
学习·离散数学
AI职业加油站3 天前
AI智能体应用工程师证书:政策红利下的职业新风口
大数据·运维·人工智能·学习·职场发展
旖旎夜光3 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
奇思妙想聪明勤奋的小羊3 天前
DeepAgents第5章:子Agent 与上下文隔离—让 Agent学会委派
人工智能·python·学习·语言模型
霍霍的袁3 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
彧azz3 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
我爱cope3 天前
【操作系统 | 计算机硬件:CPU、内存与 I/O 如何支撑操作系统?】
学习·操作系统