在现代分布式系统中Kafka 作为高性能、高吞吐的消息中间件被广泛应用。然而很多开发者在使用 Kafka 时常常会遇到两个核心问题消息顺序错乱消息丢失或重复消费本文将从原理 实战 反例 注意事项四个维度手把手教你如何在 Spring Boot 项目中正确使用 Kafka 来保障消息的顺序性与可靠性即使是小白也能轻松掌握一、需求场景为什么需要顺序性和可靠性假设你正在开发一个电商订单系统用户下单 → 支付成功 → 发货 → 完成订单这些事件必须严格按顺序处理否则会出现“未支付就发货”等严重逻辑错误。同时每条消息都不能丢比如支付成功消息丢了用户白嫖了也不能重复处理比如重复发货。这就要求我们保证消息顺序性Ordering保证消息可靠性At-least-once / Exactly-once避免极端情况下的消息丢失和重复消费二、Kafka 如何保证消息顺序性✅ 正确做法单分区Partition内有序Kafka 的设计原则是同一个 Partition 内的消息是严格有序的但不同 Partition 之间无法保证顺序。所以要保证某类消息如某个订单ID的所有事件有序必须将它们发送到同一个 Partition。 Spring Boot 实现方式// 自定义 Partitioner根据 orderId 路由到固定分区 public class OrderIdPartitioner implements Partitioner { Override public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) { ListPartitionInfo partitions cluster.partitionsForTopic(topic); int numPartitions partitions.size(); if (key instanceof String) { // 使用 orderId 作为 key确保相同 orderId 进入同一分区 return Math.abs(key.hashCode()) % numPartitions; } return 0; } Override public void close() {} Override public void configure(MapString, ? configs) {} }配置 Producer# application.yml spring: kafka: producer: bootstrap-servers: localhost:9092 key-serializer: org.apache.kafka.common.serialization.StringSerializer value-serializer: org.springframework.kafka.support.serializer.JsonSerializer properties: partitioner.class: com.example.demo.config.OrderIdPartitioner发送消息时指定 keyService public class OrderEventProducer { Autowired private KafkaTemplateString, OrderEvent kafkaTemplate; public void sendOrderEvent(String orderId, OrderEvent event) { // 关键使用 orderId 作为 key kafkaTemplate.send(order-topic, orderId, event); } }✅效果所有orderId1001的消息都会进入同一个 Partition消费者按顺序消费。三、如何保证消息不丢失可靠性Kafka 可靠性三要素Producer 端配置项推荐值作用acksall或-1要求所有 ISR 副本确认写入retriesInteger.MAX_VALUE无限重试配合幂等enable.idempotencetrue开启幂等防止重试导致重复✅ 正确配置application.ymlspring: kafka: producer: acks: all retries: 2147483647 # Integer.MAX_VALUE enable-idempotence: true max-in-flight-requests-per-connection: 5 # 幂等下可 1enable.idempotencetrue会自动设置acksall和retriesInteger.MAX_VALUE并启用 Producer ID Sequence Number 机制确保即使重试也不会产生重复消息在单个 Producer 生命周期内。四、如何避免重复消费Consumer 端即使 Producer 做了幂等网络抖动或 Consumer 异常仍可能导致重复消费。✅ 解决方案业务层幂等 手动提交偏移量1. 手动 ACK关闭自动提交spring: kafka: consumer: bootstrap-servers: localhost:9092 group-id: order-group auto-offset-reset: earliest enable-auto-commit: false # 关键手动控制 offset key-deserializer: org.apache.kafka.common.serialization.StringDeserializer value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer2. 消费者代码先处理业务再提交 offsetKafkaListener(topics order-topic) public void listen(ConsumerRecordString, OrderEvent record, Acknowledgment ack) { String orderId record.key(); OrderEvent event record.value(); try { // 1. 幂等处理用 orderId eventType 做去重如 Redis Set 或 DB 唯一键 if (idempotentService.isProcessed(orderId, event.getType())) { log.info(消息已处理跳过: {}, orderId); ack.acknowledge(); // 仍需提交 offset return; } // 2. 执行业务逻辑 orderService.handleEvent(event); // 3. 标记为已处理原子操作 idempotentService.markAsProcessed(orderId, event.getType()); // 4. 手动提交 offset ack.acknowledge(); } catch (Exception e) { log.error(处理失败不提交 offset下次重试, e); // 不调用 ack.acknowledge()offset 不提交消息会重试 } }⚠️关键点只有业务成功 去重标记成功后才提交 offset五、反例警示这些写法会导致消息乱序/丢失/重复❌ 反例1不指定 key消息随机分发// 错误没有 key消息可能分散到多个分区顺序无法保证 kafkaTemplate.send(order-topic, event);→ 后果同一订单的“支付”和“发货”消息可能乱序处理❌ 反例2自动提交 offset 异步处理KafkaListener(topics order-topic) public void listen(OrderEvent event) { // 自动提交 offset默认 5 秒一次 CompletableFuture.runAsync(() - { orderService.handleEvent(event); // 异步处理 }); }→ 后果Consumer 在处理前就提交了 offset若处理失败消息永久丢失❌ 反例3Producer 未开启幂等重试导致重复# 错误配置 spring: kafka: producer: acks: 1 # 只需 Leader 确认 retries: 3 # 重试 3 次 # 未开启 enable-idempotence→ 后果网络超时重试时可能发送多条相同消息六、注意事项 最佳实践场景建议顺序性要求高按业务 ID如 userId/orderId作为 key 发送避免消息丢失Producer 设置acksallenable.idempotencetrue避免重复消费Consumer 手动提交 offset 业务层幂等Redis/DB 唯一键Exactly-Once 语义可考虑 Kafka 事务TransactionalKafkaTransactionManager但性能有损耗消费者异常不要吞异常确保失败时不提交 offset批量消费若使用batchListener需整体成功才提交 offset七、总结目标实现方式顺序性同一业务 ID 使用相同 key → 进入同一 Partition不丢失Produceracksall 幂等 重试不重复Consumer手动 ACK 业务幂等只要掌握以上三点就能在绝大多数场景下安全可靠地使用 Kafka视频看了几百小时还迷糊关注我几分钟让你秒懂发点评论可以给博主加热度哦