RabbitMQ经典三问

RabbitMQ如何保证消息不会丢失?

可能会造成消息丢失的原因

  • 生产者方面,当生产者发送消息到 Broker 时,由于网络问题或者自身问题没有达到
  • 消息到达Broker,但是当 Broker 持久化的时候,RabbitMQ宕机
  • 消费者方面,消费者在接收消息时,出现宕机或者自身服务问题导致消息没收到

解决方法

  • 生产端要做 confirm 机制, 当消息发送给 Broker 时,Broker都要告诉生产者。如果失败了,可以将失败的消息保存到数据库中,采用定期扫描的方式尝试重新推送。
  • 消费端要做 手动ack 机制,当消费者消费成功之后,要告诉RabbitMQ删除队列中的消息。
    • 这样可能还存在一个问题,就是消费端返回 ack 时,突然宕机,由于消费者消费完了,但是队列中的消息还存在,就有可能造成 重复消费 的问题

RabbitMQ 如何避免重复消费?

造成重复消费的原因

  • 生产者:重复推送一条数据,比如:多次调用 Controller 接口,没有做接口幂等性导致
  • MQ端:消费者消费成功,响应 ack 时,MQ挂掉了,导致MQ认为还未消费这条数据,当MQ恢复后,继续推送这条数据导致重复消费
  • 消费端:消费者消费完,正准备响应 ack 时,消费者挂掉了 ,消费者恢复之后,MQ仍然认为没有消费成功。

解决方法

  • 使用数据库唯一约束

但是它局限性比较大,仅能在数据库新增时生效,并且性能较低

  • 在生产端将接口设计成幂等性, 防止重复推送同一条数据
  • 使用防重表(Redis/MySQL), 插入消费记录

当消费者开始消费的时候,先在防重表 中插入一条记录,记录当前记录的状态为消费中

  • 如果能插入成功,说明这条消息还没有消费过,去正常执行业务代码即可。
    • 当业务代码执行失败时,将该条记录在 防重表 中删除,继续重试
  • 如果插入失败,说明这条消息正在消费中或者已经消费过,但是由于某些原因导致未删除记录。
    • 此时在判断这条消息是否已经消费过,消费过则返回成功结束,没有消费过,可以利用延时队列进行重试!

可以利用Redis防重表 中插入一条记录时,设置一个过期时间,为了避免在执行完业务代码、更新业务状态时出现异常而导致重复消费。

并且还可以记录一个 消费次数 的字段 , 当一条消息被多次消费 仍然不成功时,可以记录到日志中,由具体的开发人员分析到底是什么原因,具体分析!

RabbitMQ如何解决消息堆积问题?

产生消息堆积的原因

  • 消费者宕机积压

  • 消费者消费能力不足积压

  • 发送者发送流量太大

解决方法

  • 简化消费者的逻辑,减少耗时,提高消费速度
  • 如果存在无法处理的消息,使用死信队列,防止堵塞
  • 上线更多的消费者,进行正常消费
相关推荐
青铜爱码士3 小时前
redis+lua+固定窗口实现分布式限流
redis·分布式·lua
啊喜拔牙4 小时前
如何搭建spark yarn模式的集群
大数据·分布式·spark
听雨·眠5 小时前
关于kafka
分布式·kafka·消息队列
TE-茶叶蛋5 小时前
NestJS + Kafka 秒杀系统完整实践总结
分布式·kafka
慧一居士6 小时前
Kafka批量消费部分处理成功时的手动提交方案
分布式·后端·kafka
搞不懂语言的程序员6 小时前
如何实现Kafka的Exactly-Once语义?
分布式·kafka·linq
ErizJ6 小时前
Golang|分布式索引架构
开发语言·分布式·后端·架构·golang
zcyf08097 小时前
kafka理论学习汇总
java·分布式·学习·kafka
xiaoxi6668 小时前
Dubbo实战:四步实现注册中心平滑迁移
分布式·nacos·dubbo·注册中心
刘翔在线犯法10 小时前
如何搭建spark yarn模式的集合集群
大数据·分布式·spark