1.幂等性设计原则
1.唯一标识
每条消息需携带全局唯一ID用于追踪消息生命周期
2.状态机制
业务逻辑设计应基于状态转移(如订单状态从待支付->已支付)避免重复操作状态
3幂等性校验层
在消费者处理消息前,通过校验层如数据库,缓存判断消息是否被处理
2.技术常见方案
数据库唯一约束
实现方式
将消息ID或业务唯一建如订单号设为数据困唯一索引
消费者处理消息时,先尝试插入记录,若冲突则跳过
优点
简单直接,天然放重复
缺点
高并发场景下频繁插入可能影响性能
消息去重表
创建独立表,存储消息ID或过期时间
消费者处理消息前,先查询该表:存在则跳过,不存在则插入
优化点
使用redis缓存替代数据库,提升查询效率
设置合理的过期时间,避免内存泄漏
乐观锁版本控制
实现方式
业务表中增加版本号字段如version
更新数据时校验版本号,仅当版本号匹配时才执行操作,并递增版本号
:分布式锁
- 实现方式
- 使用Redis的
SETNX
或ZooKeeper临时节点,以消息ID为锁键。 - 处理消息前获取锁,处理完成后释放锁。
- 使用Redis的
- 注意
- 需设置锁超时时间,避免死锁。
- 适用于低并发场景,高并发时锁竞争可能影响性能。
方案5:MQ内置幂等性
- Kafka
- 生产者启用
enable.idempotence=true
(确保单分区内消息不重复)。 - 消费者需自行处理跨分区的重复消息。
- 生产者启用
- RocketMQ
- 设置消息键(
KEYS
),Broker保证同一键的消息仅投递一次。 - 需业务逻辑保证键的唯一性(如订单号)。
- 设置消息键(
三、消费者端关键实践
- 先处理业务,后提交偏移量
- 确保消息处理完成且幂等校验通过后,再提交消费偏移量(ACK)。
- 若处理失败,消息会被重新投递,依赖消费者重试逻辑。
- 重试机制设计
- 限制重试次数(如最多3次),避免无限循环。
- 重试间隔采用指数退避(如2秒、4秒、8秒)。
- 死信队列(DLQ)
- 超过重试次数的消息转入死信队列,人工介入处理。