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如何解决消息堆积问题?

产生消息堆积的原因

  • 消费者宕机积压

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

  • 发送者发送流量太大

解决方法

  • 简化消费者的逻辑,减少耗时,提高消费速度
  • 如果存在无法处理的消息,使用死信队列,防止堵塞
  • 上线更多的消费者,进行正常消费
相关推荐
茶杯梦轩5 天前
从零起步学习RabbitMQ || 第三章:RabbitMQ的生产者、Broker、消费者如何保证消息不丢失(可靠性)详解
分布式·后端·面试
回家路上绕了弯6 天前
深入解析Agent Subagent架构:原理、协同逻辑与实战落地指南
分布式·后端
用户8307196840826 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
用户8307196840828 天前
RabbitMQ vs RocketMQ 事务大对决:一个在“裸奔”,一个在“开挂”?
后端·rabbitmq·rocketmq
初次攀爬者9 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
初次攀爬者11 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
让我上个超影吧12 天前
消息队列——RabbitMQ(高级)
java·rabbitmq
塔中妖12 天前
Windows 安装 RabbitMQ 详细教程(含 Erlang 环境配置)
windows·rabbitmq·erlang
断手当码农12 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者13 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端