欢迎光临
我们一直在努力

RabbitMQ 消费端幂等实战(重复消息、去重、重放怎么处理)

这篇把“幂等”从概念拉回工程现实:重复消息不可避免,但结果可以可控。

先说结论

消费端幂等不是一个技巧,而是三件事组合:

  • 唯一标识:每条消息都有可追踪的 messageId
  • 去重存储:Redis 或数据库记录“是否处理过”
  • 业务可重放:重复消费不会产生副作用

  • 一、为什么会有重复消息

    你只要开启了可靠投递和手动 ACK,就一定会遇到重复消息。常见场景:

    • 消费成功,但 ACK 失败
    • 消费失败后重试
    • 生产者超时重发

    这不是异常,是系统设计的正常行为。


    二、3 种幂等实现方式(按成本从低到高)

    1) Redis 去重(推荐起步)

    优点:简单、高性能
    缺点:Redis 不可用时要兜底

    public void onMessage(OrderMessage msg) {
    String dedupKey = "mq:dedup:" + msg.getMessageId();

    // SETNX + TTL
    Boolean first = redisTemplate.opsForValue()
    .setIfAbsent(dedupKey, "1", 24, TimeUnit.HOURS);

    if (Boolean.FALSE.equals(first)) {
    // 重复消息,直接 ACK
    return;
    }

    // 业务处理
    process(msg);
    }

    2) 数据库唯一索引(可靠优先)

    优点:强一致性
    缺点:写入成本更高

    CREATE TABLE mq_consume_log (
    message_id VARCHAR(64) PRIMARY KEY,
    status TINYINT,
    create_time DATETIME
    );

    public void onMessage(OrderMessage msg) {
    try {
    // 先插入去重表
    consumeLogMapper.insert(msg.getMessageId());
    } catch (DuplicateKeyException e) {
    // 重复消息
    return;
    }

    process(msg);
    }

    3) 业务幂等(最终形态)

    比如:支付成功后只更新一次状态,重复消息也只是“幂等更新”。

    public void process(OrderMessage msg) {
    // 只更新一次
    orderMapper.updateStatusIfNotPaid(msg.getOrderId());
    }


    三、常见业务场景怎么做

    场景 1:扣库存

    不要直接 stock – 1,而是做“去重后扣减”:

    public void reduceStock(String orderNo) {
    if (dedup(orderNo)) {
    stockMapper.decrease(orderNo);
    }
    }

    场景 2:发优惠券

    用“唯一索引”锁住发放记录:

    ALTER TABLE user_coupon
    ADD UNIQUE KEY uk_user_coupon(user_id, coupon_id);

    重复发放自然失败,不影响业务。

    场景 3:更新订单状态

    只允许状态单向流转:

    UPDATE orders
    SET status = 'PAID'
    WHERE id = ? AND status = 'UNPAID';

    重复消费只会影响 0 行。


    四、一个“够用”的组合方案

    如果你不想纠结,直接用这个:

  • messageId 必须有
  • Redis 去重
  • 数据库状态更新做幂等条件
  • 这是我在实际项目里用的最平衡方案,成本低、效果稳。


    五、常见坑

  • 去重 key 没有 TTL
    Redis 记录会无限增长,记得设置过期时间。

  • messageId 不唯一
    不要用订单号当 messageId,最好是 UUID 或雪花 ID。

  • 只靠 Redis 去重
    Redis 挂了就会穿透,建议加业务幂等作为第二道保险。


  • 最后总结

    幂等不是让系统“完全不重复”,而是让重复“变得无害”。

    你只要把这三件事做好:

  • 消息有唯一标识
  • 去重有记录
  • 业务可重放
  • 重复消息就不再是线上事故,而是可控事件。

    赞(0)
    未经允许不得转载:171主机测评 » RabbitMQ 消费端幂等实战(重复消息、去重、重放怎么处理)
    分享到: 更多 (0)

    评论 抢沙发

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