欢迎光临
我们一直在努力

Kafka 消息为什么不会丢?ACK、ISR 和副本机制详解

在学习 Kafka 时,经常会看到一句话:Kafka 可以保证消息不丢失。
但严格来说,这句话并不完整。
Kafka 并不是“无论怎么配置、无论发生什么故障都绝对不会丢消息”,而是通过 副本机制、ISR、ACK 确认机制、min.insync.replicas、生产者重试和幂等性 等多层机制,把消息丢失的风险尽可能降低。
真正应该记住的是:

Kafka 的可靠性来自一整套机制配合,而不是某一个配置项。
这篇文章就从一条消息发送到 Kafka 的完整过程出发,把 acks、Leader/Follower、副本、ISR、HW/LEO 以及生产环境常见配置一次讲清楚。


一、先看结论:Kafka 靠什么降低消息丢失风险?
一条消息要可靠地进入 Kafka,核心会经过下面几层保护:
Producer 将消息发送给分区的 Leader。
Leader 把消息追加到自己的日志。
Follower 从 Leader 拉取数据并复制到自己的日志。
Kafka 维护 ISR,剔除长时间无法跟上 Leader 的副本。
Producer 通过 acks 决定需要等待到什么程度才认为发送成功。
min.insync.replicas 限制 ISR 太少时是否还允许继续写入。
Leader 故障后,Kafka优先从安全的副本集合中重新选举 Leader。
Producer 通过重试和幂等性处理临时网络故障,减少丢失和重复写入问题。
在这里插入图片描述

所以 Kafka 的可靠性并不是单点机制,而是从 生产者 → Broker → 副本 → 故障恢复 一层一层保证的。

二、Kafka 为什么需要副本?
Kafka 的数据不是以 Topic 为最小副本单位,而是以 Partition(分区) 为复制单位。
假设有一个 Topic:

order-topic

其中 Partition 0 配置了 3 个副本:

Broker 1:Leader
Broker 2:Follower
Broker 3:Follower

这里的副本数就是:

replication.factor = 3

在正常情况下,一个 Partition 只有一个 Leader,另外的副本作为 Follower。
Producer 写消息时,首先写入 Leader;Follower 再不断从 Leader 拉取消息并复制到自己的日志中。Kafka 官方文档也明确说明,一个分区的复制单位就是 Partition,Follower 会持续复制 Leader 的日志。
为什么不能只保存一份?
如果只有 Leader 一份数据:

Producer

Leader

Leader 所在 Broker 一旦发生磁盘损坏或者机器故障,这部分数据就可能直接不可用甚至丢失。
有副本以后:

┌── Follower 1
Producer → Leader
└── Follower 2

即使 Leader 挂掉,只要有合适的 Follower 保存了已经提交的数据,就可以从剩余副本中恢复。
这就是 Kafka 可靠性的第一层:副本冗余。

三、Leader 和 Follower 分别负责什么?

  • Leader
    Leader 是这个 Partition 当前的主要副本。
    Producer 的写入会发送给 Leader。
    可以简单理解成:
  • Producer → Leader

    Leader 收到消息后追加到自己的日志中,再由 Follower 复制。
    2. Follower
    Follower 不负责决定消息顺序,它会持续从 Leader 拉取消息,让自己的日志尽量追上 Leader。

    Leader

    Follower 1
    Follower 2

    如果 Leader 发生故障,Kafka 会进行 Leader 选举,让满足条件的副本接替 Leader。
    但这里马上会出现一个关键问题:

    是不是所有 Follower 都能直接成为新的 Leader?
    不是。
    因为有些 Follower 可能已经落后很多消息。
    这就引出了 Kafka 中非常重要的概念:ISR。


    四、ISR 到底是什么?
    ISR 的全称是:

    In-Sync Replicas

    即:与 Leader 保持同步的一组副本。
    假设一个 Partition 有三个副本:

    Leader
    Follower 1
    Follower 2

    正常情况下:

    ISR = [Leader, Follower 1, Follower 2]

    如果 Follower 2 因为网络、机器负载或其他原因长时间跟不上 Leader,它就可能被移出 ISR:

    ISR = [Leader, Follower 1]

    Kafka 4.3 的 Broker 配置中,replica.lag.time.max.ms 用于判断 Follower 是否长时间没有追上 Leader;默认值为 30 秒。超过这个条件后,Follower 会被移出 ISR。
    这一步非常重要。
    因为 Kafka 不能让一个严重落后的副本还被当成“安全副本”。否则 Leader 一挂,如果直接让这个落后的 Follower 上位,刚写进去的数据就可能消失。
    因此可以这样记:

    副本是“我有数据副本”,ISR 是“我现在仍然跟得上 Leader,可以被认为是同步副本”。


    五、ACK 是什么?
    Producer 把消息发送给 Kafka 后,需要知道:

    这条消息到底算不算发送成功?
    这个确认级别由:

    acks

    控制。
    Kafka 当前支持三个主要级别:

    acks=0
    acks=1
    acks=all

    在这里插入图片描述


    六、acks=0:发出去就不管了
    配置:

    acks=0

    Producer 把消息写入网络缓冲区后就认为发送完成,不等待 Broker 的任何确认。
    流程类似:

    Producer → Kafka
    Producer:我已经发出去了,继续干别的

    这种方式速度快、等待时间少,但可靠性最低。
    例如 Producer 刚把数据发出去,此时:
    网络断了
    Broker 没收到
    Leader 正好发生故障
    Producer 都可能不知道。
    Kafka 官方 Producer 配置说明中也明确指出,acks=0 时无法保证服务端已经收到消息,而且 Producer 通常无法感知发送失败,因此 retries 也无法正常发挥作用。
    适合什么场景?
    更适合对少量丢失不敏感、极端追求吞吐或延迟的场景。
    对于订单、支付、库存等重要业务消息,一般不应该这样配置。

    七、acks=1:Leader 写成功就返回
    配置:

    acks=1

    流程:

    Producer

    Leader 写入本地日志

    返回 ACK

    注意:Leader 返回 ACK 时,不要求所有 Follower 已经复制完成。
    于是可能发生这种情况:

    1. Producer 发送 message-A
    2. Leader 写入 message-A
    3. Leader 返回 ACK
    4. Follower 还没有复制 message-A
    5. Leader 突然宕机

    此时新的 Leader 如果来自还没有复制到 message-A 的副本,这条消息就可能丢失。
    所以:

    acks=1 比 acks=0 可靠,但依然存在 Leader 已确认、Follower 尚未完成复制时的数据丢失窗口。


    八、acks=all:可靠性最强
    配置:

    acks=all

    或者:

    acks=-1

    二者含义相同。
    acks=all 表示 Leader 要等待 当前 ISR 中的全部副本确认收到这次写入,才会向 Producer 返回成功。
    假设:

    ISR = [Leader, Follower 1, Follower 2]

    那么流程可以理解为:

    Producer

    Leader

    Follower 1
    Follower 2

    ISR 中副本确认

    Producer 收到成功结果

    因此即使 Leader 随后发生故障,只要还有至少一个已经同步的安全副本存活,已经成功确认的消息仍然可以用于故障恢复。
    Kafka 4.3 Producer 当前的 acks 默认值就是:

    all

    这是三个 ACK 级别中最强的持久性保证。

    九、一个特别容易搞错的地方:acks=all ≠ 所有副本
    很多人第一次看到 all,会理解成:

    replication.factor 有 3 个副本,就必须等 3 个副本。
    这个说法不够准确。
    acks=all 等待的是:
    当前 ISR 中的全部副本。
    例如最初:

    replication.factor = 3
    ISR = [Leader, Follower 1, Follower 2]

    这时 acks=all 会等待这 3 个 ISR 副本。
    但如果 Follower 2 已经故障并被移出 ISR:

    ISR = [Leader, Follower 1]

    此时 acks=all 等待的就是当前 ISR 中这 2 个副本。
    那么又有一个问题:

    如果只剩 Leader 自己还在 ISR,acks=all 会不会也成功?
    如果没有其他限制,确实可能。
    这就是为什么还需要 min.insync.replicas。


    十、min.insync.replicas 是什么?
    min.insync.replicas 可以理解成:

    当 Producer 使用 acks=all 时,Kafka 至少要求 ISR 中还存在多少个副本,才允许这次写入成功。
    例如生产环境常见配置:

    replication.factor = 3
    min.insync.replicas = 2
    acks = all

    在这里插入图片描述

    情况 1:三个副本都正常

    ISR = [Leader, Follower 1, Follower 2]

    满足:

    ISR 数量 = 3 >= 2

    正常写入。
    情况 2:一个 Follower 挂了

    ISR = [Leader, Follower 1]

    满足:

    ISR 数量 = 2 >= 2

    依然允许写入。
    情况 3:只剩 Leader

    ISR = [Leader]

    此时:

    ISR 数量 = 1 < 2

    Kafka 会拒绝写入,Producer 会收到类似 NotEnoughReplicas 或 NotEnoughReplicasAfterAppend 的异常。
    这看起来好像“Kafka 挂了”,实际上它是在主动做取舍:

    宁愿暂时不能写,也不要只保存一份数据然后告诉 Producer 写成功。
    这就是典型的:可用性与数据可靠性之间的权衡。


    十一、为什么 replication.factor=3 + min.insync.replicas=2 很常见?
    组合:

    replication.factor = 3
    min.insync.replicas = 2
    acks = all

    可以做到:
    正常情况下有 3 份副本。
    允许损坏 1 个副本后继续写入。
    当只剩 1 个同步副本时拒绝继续确认高可靠写入。
    因此它在可靠性和可用性之间比较均衡。
    例如创建 Topic 时可以这样配置:

    bin/kafka-topics.sh –create –topic order-events –bootstrap-server localhost:9092 –partitions 3 –replication-factor 3 –config min.insync.replicas=2

    生产者则使用:

    acks=all
    enable.idempotence=true

    注意,Kafka 4.3 中 Producer 默认已经是 acks=all,并且在没有冲突配置时,enable.idempotence 默认启用。但在学习和生产配置中,把关键可靠性参数明确写出来通常更容易阅读和维护。

    十二、ISR 为什么能降低 Leader 故障时的数据丢失风险?
    假设当前:

    ISR = [Broker 1, Broker 2, Broker 3]

    其中:

    Broker 1 = Leader
    Broker 2 = Follower
    Broker 3 = Follower

    Producer 使用:

    acks=all

    一条消息已经被确认成功,意味着它已经到达当前 ISR 所要求的复制条件。
    如果此时 Broker 1 突然宕机,Kafka 会进行 Leader 故障恢复,从满足安全条件的副本中选出新的 Leader。
    因此新的 Leader 能继续携带已经提交的数据。
    Kafka 官方设计文档给出的核心保证是:

    已提交的消息,在始终至少存在一个同步副本存活的前提下,不会因为 Leader 故障而丢失。
    所以 ISR 的意义不仅是“记录谁同步了”,更重要的是:
    它决定了哪些副本可以被认为拥有足够新的数据来参与安全恢复。


    十三、HW 和 LEO 又是什么?
    在理解副本同步时,经常会看到两个概念:

    LEO
    HW

  • LEO:Log End Offset
    可以把 LEO 直观理解为:
  • 某个副本当前日志写到哪里了。
    例如:

    Leader LEO = 11
    Follower 1 LEO = 10
    Follower 2 LEO = 8

    说明各个副本的复制进度不同。
    2. HW:High Watermark
    HW 可以直观理解为 Kafka 已经推进到的安全提交/可见边界。
    在这里插入图片描述

    Leader 的日志末尾可能已经有一些新消息,但这些消息还没有完成 ISR 所要求的同步条件。
    所以:

    Leader LEO

    往往可能比:

    HW

    更靠后。
    这也是为什么不能简单认为:

    “Leader 本地已经写进日志 = 消息已经完全安全。”
    Kafka 会区分“Leader 已经拥有的数据”和“已经达到提交条件的数据”。


    十四、Producer 重试为什么也很重要?
    即使 Broker 端已经有副本机制,Producer 仍然可能遇到:
    网络抖动
    Leader 切换
    请求超时
    临时 Broker 故障
    这种情况下,如果 Producer 完全不重试,一次短暂故障就可能让消息发送失败。
    Kafka Producer 提供:

    retries

    当前 Kafka 4.3 Producer 的默认 retries 已经是一个非常大的值,官方更建议通过 delivery.timeout.ms 控制一次消息发送整体允许的重试时间。
    但重试会带来另一个问题:

    Producer → Broker
    Broker 已经写成功
    ACK 返回过程中网络断开
    Producer 没收到 ACK
    Producer 再次发送

    这时 Broker 可能收到两次相同消息。
    因此 Kafka 又提供了:

    enable.idempotence


    十五、enable.idempotence:防止 Producer 重试导致重复写入
    配置:

    enable.idempotence=true

    启用幂等生产者后,Kafka 会避免因为 Producer 的重试导致同一条记录被重复写入日志。
    Kafka 4.3 中,在没有冲突配置的情况下,幂等性默认启用。
    启用幂等性要求:

    acks = all
    retries > 0
    max.in.flight.requests.per.connection <= 5

    当前默认的 max.in.flight.requests.per.connection 为 5。
    所以对于重要消息,推荐思路通常是:

    acks=all
    enable.idempotence=true

    再配合 Broker / Topic 端:

    replication.factor = 3
    min.insync.replicas = 2

    形成比较完整的可靠性链路。

    十六、Kafka 在什么情况下仍然可能丢消息?
    这部分非常重要。
    不要因为使用了 Kafka 就认为消息绝对不会丢。
    情况 1:使用 acks=0

    acks=0

    Producer 不等服务器确认,本身就没有可靠发送保证。
    情况 2:使用 acks=1,Leader 刚确认就故障

    acks=1

    Follower 可能还没来得及复制。
    情况 3:副本因子只有 1

    replication.factor = 1

    只有一份数据,Broker 或磁盘发生不可恢复故障时,就没有其他副本可用。
    Kafka 4.3 中 default.replication.factor 的默认值仍然是 1,因此生产环境不能只看到 Producer 默认 acks=all 就认为可靠性配置已经完整。
    情况 4:acks=all,但 min.insync.replicas 太低
    例如:

    replication.factor = 3
    min.insync.replicas = 1

    只剩一个 ISR 副本时仍可能接受写入,随后这个唯一副本再发生故障,风险就会明显增大。
    情况 5:开启非同步副本的 Leader 选举
    Kafka 的配置:

    unclean.leader.election.enable

    允许不在 ISR 中的副本在必要时成为 Leader。
    这样做可以提高某些极端故障下的可用性,但可能带来数据丢失。
    Kafka 4.3 中这个配置默认是:

    false

    也就是说默认更偏向数据安全。
    情况 6:所有同步副本的数据都不可恢复
    任何副本机制都不是无限可靠。
    如果一个 Partition 的所有有效副本都同时发生不可恢复的数据损坏,就已经超出了“还有同步副本可恢复”的前提。

    十七、推荐的可靠性配置组合
    对于订单、支付、库存、交易事件等比较重要的消息,可以把下面这套配置作为理解可靠性的基础模板。
    Topic:

    replication.factor = 3
    min.insync.replicas = 2

    Producer:

    acks=all
    enable.idempotence=true

    同时保持:

    unclean.leader.election.enable = false

    整体逻辑就是:

    Producer

    acks=all

    Leader

    ISR Followers

    至少保持足够数量的同步副本

    发送成功

    这样,即使某台 Broker 出现故障,也有其他同步副本可以继续承担数据恢复工作。

    十八、acks、ISR、min.insync.replicas 三者到底是什么关系?
    这是整篇文章最核心的部分。
    acks
    解决:

    Producer 要等到什么程度才认为消息发送成功?
    ISR
    解决:
    当前哪些副本仍然被认为和 Leader 保持同步?
    min.insync.replicas
    解决:
    当使用 acks=all 时,ISR 至少还要剩多少个副本,Kafka 才允许继续成功写入?
    三者配合:

    Producer

    │ acks=all

    Leader

    ├── Follower 1 ┐
    └── Follower 2 ├── ISR

    min.insync.replicas


    判断是否允许写入

    一句话记忆:

    acks 决定“等谁”,ISR 决定“谁算同步副本”,min.insync.replicas 决定“同步副本少到什么程度就不写了”。


    十九、常见误区
    误区 1:acks=all 就绝对不丢
    错误。
    还要看:

    replication.factor
    min.insync.replicas
    ISR 状态
    Leader 选举策略
    副本是否还能恢复

    误区 2:acks=all 就是等 replication.factor 个副本
    不准确。
    它等待的是:

    当前 ISR 中的全部副本

    误区 3:min.insync.replicas=2 就是只等两个 ACK
    不准确。
    它首先是一个最小 ISR 数量门槛。
    当前 Kafka 文档还特别说明:当 acks=all 时,是当前 ISR 中所有副本都要确认;min.insync.replicas 决定 ISR 少于多少时直接失败。
    误区 4:Follower 越多越好
    副本越多,数据冗余能力通常越强,但同时也会增加:
    存储空间
    网络复制流量
    Broker I/O
    故障恢复和运维成本
    所以副本数不是无限增加,而是根据可靠性要求和集群规模选择。
    误区 5:Producer 收到成功就等于业务绝对安全
    Kafka 解决的是消息在消息系统中的可靠存储和传输问题。
    业务侧仍然需要考虑:
    消费成功后何时提交 Offset
    消费失败如何重试
    数据库事务是否成功
    消费者幂等
    重复消息
    这些属于消费者可靠性和端到端一致性问题,不能只靠 Producer 的 ACK 解决。

    二十、最后总结
    Kafka 消息可靠性的核心,不是“有一个神奇配置让消息永远不会丢”,而是一套机制共同作用:

    副本机制
    +
    Leader / Follower
    +
    ISR
    +
    acks=all
    +
    min.insync.replicas
    +
    Producer retries
    +
    enable.idempotence

    其中最重要的逻辑可以记成:

    Producer 把消息写给 Leader

    Follower 从 Leader 复制

    Kafka 维护 ISR

    acks 决定 Producer 等待的确认级别

    min.insync.replicas 防止同步副本太少仍继续确认写入

    Leader 故障后从安全副本中恢复

    如果只记一句话:

    Kafka 所谓“消息不丢”,本质是通过多副本保存数据,用 ISR 筛选安全副本,再通过 ACK 和最小 ISR 门槛决定什么时候才能向 Producer 宣布写入成功。
    这才是 Kafka 可靠性机制真正的核心。


    参考资料
    Apache Kafka 4.3 Design:Replication / ISR / durability
    Apache Kafka 4.3 Producer Configs:acks、retries、enable.idempotence
    Apache Kafka 4.3 Topic Configs:min.insync.replicas
    Apache Kafka 4.3 Broker Configs:replica.lag.time.max.ms、unclean.leader.election.enable

    版本说明:本文按 Apache Kafka 4.3 官方文档整理。Kafka 4.0+ 还引入了 Eligible Leader Replicas(ELR)机制;启用 ELR 时,min.insync.replicas 的部分语义会发生扩展。本文聚焦最常用的 ISR + ACK + 副本可靠性主线,便于理解基础机制。

    赞(0)
    未经允许不得转载:171主机测评 » Kafka 消息为什么不会丢?ACK、ISR 和副本机制详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址