Kafka如何解决消息重复与乱序?详解Kafka的幂等机制!

对于高性能的消息队列来说,在开发中消息重复与乱序是必须要考虑的问题。重复消息会引发业务逻辑的重复执行,乱序消息则会破坏数据一致性,直接影响系统的可靠性与稳定性。而 Kafka 作为经典的高吞吐的延迟队列,其内置的幂等机制,正是应对这类问题的关键技术之一。本文将深入拆解 Kafka 幂等的底层逻辑,希望能对大家有所帮助。

出错场景

消息重复

假设当前 Kafka 设置的 acks = 1,即 Producer 发送消息后会等待 Leader 副本的响应。如果 Leader 副本所在的 Broker 节点没有返回给Producer ACK,那么就会重发消息。

假设当前消息已经顺利发到 Broker 中,Broker 正准备返回 ACK 给 Producer。如果这时候发生网路问题,ACK 在发送的过程中丢失了,Producer 没有收到 ACK,就会认为自己的消息没有发送成功,就会再次发送同样的消息。但消息已经存在于 Broker 中了,再发一次不就导致消息重复了吗?

消息乱序

Kafka 在幂等机制的帮助下,可以一次性至多发5个消息,假设没有幂等,那么一次性发这5个消息就会出现消息乱序的问题。

不同消息发送的速率也有可能不同,假设 消息A 在 消息B 发送之前,但消息A的发送速率慢于 消息B,消息B 就有可能先到达目标 Partition,导致消息乱序。

幂等原理

在讲解幂等性原理之前,要先考虑下面几个问题:

  1. Broker 如何判断消息是否是唯一的?常见的方法就是通过特殊的业务标识设置唯一键。如果设置了唯一键,该以什么区分?
  2. 如何解决消息乱序的问题?

Kafka是是从分区的维度上设置唯一键的,因为分布式系统下全局唯一键是不好的。同时可能存在多个Producer向同一个Partition 发送消息,这多个Producer彼此发消息很难互相感知,因此唯一键还要考虑上Producer。所以,Kafka 的最终方案就是结合 Producer 和 TopicPartition的唯一键。

同时 Producer 在发送消息的同时还会发送以 Partition 为基础的序列号,从0开始随着消息的产生递增。在 Broker 端通过判断序列号是否连续来判断消息是否有序。

Kafka 通过 PID(Producer ID,每个Producer在初始化的时候都会分配一个 PID)和 Sequence Number(以TopicParititon为基础,Producer在发送消息的时候,会给每条消息标记一个Sequence Number)来生成唯一键:Producer-PID + TopicPartition-SequenceNumber。Broker来存储 Sequence Number,并判断:

  • 如果收到的新 Sequence Number 比本地的 Sequence Number 大1,说明是新消息
  • 如果相等,说明是重复消息
  • 如果收到的新 Sequence Number - 本地Sequence Number > 1,说明消息发生了乱序

具体实现

Kafka 实际发送消息不是立即发送到 Broker 的,而是先发送到 ProducerBatch中,再以 Batch 为单位发送。

Broker 通过存储一个 Map 映射来观察 TopicPartition 的状态,<PID, 分区状态>。分区状态中最重要的属性就是batchMatadata,batchMatadata主要有五个属性:

  • lastSeq:最后一个消息的序列号
  • lastOffset:最后一条消息的Offset
  • offsetDelta:最后一条消息和第一条消息的 Offset 差值
  • timestamp:最后一条消息的添加时间

发送 ProducerBatch 的时候,会以batchMatadata为根据,如果新发送的Batch 和 batchMatadata 中的某个 Batch 相同,说明消息重复,然后直接向生产者反馈消息发送成功。

还有问题未解决!

当 Producer 重启后,它的 PID 就会发生改变,幂等机制就不再成立了。因此Kafka 的幂等机制无法保证跨会话、跨分区的消息幂等。Kafka的事务机制给了解决方案,这篇文章不再讨论。

相关推荐
爱勇宝9 分钟前
没有 Fn 键关触控板?我做了一个双击即用的 Windows 小工具
前端·后端·程序员
沙湖遇雨42 分钟前
8.ByteBuf 的数据模型、生命周期和内存分配
后端
by组态1 小时前
Ricon组态系统API参考手册
前端·后端·物联网
再吃一根胡萝卜1 小时前
Agent 如何选择与生成 SQL —— Text2SQL 全链路详解
后端
苍何1 小时前
把操作流程直接录成 Skill,豆包太夯了!
后端
Go_error1 小时前
在 Go 服务层中如何优雅地管理事务?
后端·go
爱读源码的大都督2 小时前
DeepSeek面试官问:多租户 RAG 系统怎样实现细粒度权限控制?
后端·面试·架构
苍何2 小时前
我们终于成立了 AgentWork 开源社区,16.4 万字豆包工作蓝皮书同步开源(建议收藏)
后端