RabbitMQ 如何保证消息不会被重复消费

本文探讨了消息队列中如何保证消息不被重复消费,以维护系统幂等性。分析了消息重复消费的原因,包括生产者重复发送和消费者重复接收,并提出了解决方案——通过全局唯一ID确保幂等性。消费者接收到消息时,检查数据库或缓存中是否存在相同ID的消息,避免重复写入。此外,根据业务场景,可以选择使用Redis或数据库来存储消息状态,确保数据一致性。
摘要由CSDN通过智能技术生成

所有的消息队列都要保证同一条消息不会被重复消费

  • 举个例子:假设有个系统,消费一条往数据库里插入一条,要是你一个消息重复两次,你不就插入了两条,这数据就错了
  • 所以消费到第二次的时候,自己判断一下已经消费过了,直接扔了,就保留了一条数据

一条数据重复出现两次,数据库里就只有一条数据,这就保证了系统的幂等性幂等性。

  • 一个请求重复多次,需要确保对应的数据是不会改变的,不能出错。

为什么会重复消费

(1)生产者重复发送消息:生产者在往消息队列发送消息时,发生了网络抖动,生产者没有收到确认信号,但是实际上消息队列已经收到了消息,超过一定时间后生产者会重新发送消息,这时一条消息被发送了两次;
(2)消费者重复接受消息:消费者成功消费消息后,发生了网络抖动,消息队列没有收到确认信号,超过一段时间后会重新给消费者投递相同的消息,同一条消息即存在被消费两次的可能。

如何解决

通用解决方案是在消息实体中添加全局唯一的id,例如 msg_id(消息ID),在代码中保证消息的幂等性,

  • 消费者在收到消息之后,根据 msg_id 从缓存或者数据库中查询是否存在已有消息;
  • 如果不存在已有消息,那么消费之后,将 msg_id 对应的消息实体或者序列化对象写入缓存或者数据库;
  • 如果存在已有消息,说明这条消息已被消费过,丢弃消息并且打一条告警日志。

并且可以根据重复消费的容忍程度以及性能要求选择使用缓存还是使用数据库,

  • 如果对判断的速度要求高,可以使用 Redis 作为缓存;
  • 如果对判断的稳定性和鲁棒性要求高,使用数据库存储消息实体,同时将 msg_id 作为数据库表的唯一键,插入重复记录一定会抛出异常,避免数据库因为并发问题产生脏数据,保证了消息消费的不可重复性。

结合业务分析

  • 如果是对数据库进行写库,先根据主键查一下,如果这数据都有了,就不写入
  • 如果是写redis,那没问题了,反正每次都是set,天然幂等性。
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值