Skip to content

可靠性与幂等

1. 这是什么

可靠性与幂等关注的是消息是否会丢、是否会重、业务是否能安全重复处理。
这是 Kafka 在生产系统里最关键的能力之一。

一句话理解:

  • 可靠性关注“消息链路稳不稳”
  • 幂等关注“重复来一次会不会出事故”

2. 为什么重要

消息系统最怕的不是“偶尔慢一点”,而是:

  • 消息丢了
  • 重复消费
  • 业务重复执行

所以 Kafka 的可靠性配置和业务幂等设计必须一起看。

3. 先建立直觉:开启幂等生产者不等于业务绝对不会重复

一个很常见的误区是:

  • 只要 Kafka 开了幂等,业务就永远不会重复

这不准确。
更实用的理解是:

  • 中间件可以降低链路层重复
  • 但业务最终是否能安全重复处理,仍然常常要靠消费端幂等

4. 核心内容

4.1 acks

acks 决定的是:

  • Producer 发送后,要等到什么程度才算成功

所以它直接影响:

  • 可靠性
  • 延迟
  • 吞吐

4.2 重试

重试是可靠性的重要组成部分,但重试本身也会带来:

  • 乱序风险
  • 重复风险
  • 额外压力

4.3 幂等生产者

幂等生产者的核心目标是:

  • 降低同一条消息因为重试等原因重复写入的概率

它很重要,但不等于:

  • 整条业务链天然幂等

4.4 事务消息基础认知

学习阶段先抓住一个直觉:

  • Kafka 事务更多是在消息链路层做一组操作的一致性控制

它不是替代业务数据库事务的万能工具。

4.5 至少一次、至多一次、恰好一次

这是消息语义最核心的三种表达:

  • 至少一次:可能重复,不轻易丢
  • 至多一次:可能丢,不重复
  • 恰好一次:目标最好,但实现最复杂

4.6 消费端幂等

消费端幂等常见做法包括:

  • 业务唯一键
  • 去重表
  • 状态机控制
  • 幂等 key

5. 学习重点

这一章最重要的是掌握:

  • 可靠性和吞吐通常存在权衡
  • acks 只是链路参数,不是全部答案
  • 幂等生产者很重要,但消费端幂等常常更关键
  • “恰好一次”比想象中复杂得多

6. 常见问题

6.1 只调 acks 不看整体链路

这样容易把中间件参数当成万能保险。

6.2 误以为开启幂等后业务就绝对不会重复

业务层去重和状态控制仍然非常重要。

6.3 忽视消费端去重与状态控制

这是很多重复执行事故的真正根因。

7. 动手验证

当前环境没有 Kafka CLI,这里用纯 Java demo 直接验证“重试可能带来重复、幂等能消除重复影响”的核心心智。

7.1 准备一个可运行示例

新建文件 KafkaIdempotenceDemo.java,内容如下:

java
import java.util.HashSet;
import java.util.Set;

public class KafkaIdempotenceDemo {
    public static void main(String[] args) {
        String eventId = "evt-1001";

        // 不做幂等:重试两次就执行两次
        int nonIdempotentCounter = 0;
        nonIdempotentCounter++;
        nonIdempotentCounter++;
        System.out.println("nonIdempotentCounter=" + nonIdempotentCounter);

        // 做幂等:同一个事件只处理一次
        Set<String> processed = new HashSet<>();
        int idempotentCounter = 0;
        if (processed.add(eventId)) {
            idempotentCounter++;
        }
        if (processed.add(eventId)) {
            idempotentCounter++;
        }

        System.out.println("idempotentCounter=" + idempotentCounter);
        System.out.println("processedSize=" + processed.size());
    }
}

7.2 编译并运行

bash
javac KafkaIdempotenceDemo.java
java KafkaIdempotenceDemo

7.3 你应该观察到什么

text
nonIdempotentCounter=2
idempotentCounter=1
processedSize=1

7.4 每一行在验证什么

  • nonIdempotentCounter=2:说明重试或重复消息会直接导致业务重复执行
  • idempotentCounter=1:说明幂等控制能把重复消息对业务的影响压平
  • processedSize=1:说明同一事件 ID 只被记一次

8. 练习建议

  • 总结 Kafka 常见消息语义的适用场景
  • 设计一个消费端幂等方案
  • 对比生产端配置对可靠性的影响
  • 用自己的话解释“为什么恰好一次比至少一次复杂得多”

9. 自测问题

  • acks 配置会如何影响可靠性和性能?
  • 为什么消息系统里幂等几乎是必备能力?
  • “恰好一次”为什么比想象中复杂?
  • 为什么消费端幂等常常比中间件配置更关键?

10. 自测核对要点

  • 可靠性和性能通常存在权衡
  • acks、重试、幂等生产者共同影响链路语义
  • 消费端幂等是关键防线
  • “恰好一次”不是简单一个开关,而是整条链路协同结果