RabbitMQ-问题

消息堆积

消息堆积的影响

  • 可能导致新消息无法进入队列
  • 可能导致旧消息无法丢失
  • 消息等待时间过长,超出了业务容忍范围

产生堆积的情况

  • 生产者突然大量发布消息
  • 消费者消费失败
  • 消费者出现性能瓶颈
  • 消费者挂掉

解决办法

  • 排查消费者的消费性能瓶颈
  • 增加消费者的多线程处理
  • 部署增加多个消费者

消息已经堆积如何解决

  • 看消费者是否产生了异常,先解决异常;
  • 消息队列堆积,想办法把消息转移到一个新的队列,增加服务器慢慢来消费这个消息即可
  • 生产环境的队列就可以恢复为可用状态

消息丢失

主要分为:消息在生产者丢失,消息在RabbitMQ丢失,消息在消费者丢失

消息在生产者丢失

一般是网络不稳定的原因

解决方案:

采用RabbitMQ发送方消息确认机制,当消息成功被MQ接收到时,会给生产者发送一个确认消息,表示接收成功。RabbitMQ发送消息确认模式有以下三种:普通确认模式,批量确认模式,异步监听确认模式。Spring整合RabbitMQ后只使用了异步监听确认模式。

如果没确认,可以重发。

说明:异步监听模式,可以实现边发送消息边进行确认,不影响主线程任务执行。

消息在RabbitMQ丢失

MQ服务器宕机或者重启才会出现这种情况

解决方案:

持久化交换机、队列、消息,确保MQ服务器重启时依然能从磁盘回复对应的交换机、队列和消息。Spring整合后默认开启交换机、队列、消息的持久化,所以不修改任何设置就可以保证消息不在RabbitMQ丢失。但是为了以防万一,还是可以声明下。

消息在消费者丢失

消费者消费消息的时候,如果设置为自动回复MQ,消费者端收到消息后会自动回复MQ服务器,MQ则会删除该条消息,如果消息已经在MQ被删除但是消费者的业务出现异常或者消费者服务器宕机,那么就会导致该消息没有处理成功从而导致该条消息丢失。

解决方案:

设置为手动回复MQ服务器,当消费者出现异常或者服务器宕机时,MQ服务器不会删除该消息,而是会把消息重发给绑定该队列的消费者,如果该队列只绑定了一个消费者,那么该消息会一直保存在MQ服务器,直到消费能被正常消费为止。本解决方案以一个队列绑定多个消费者为例来说明,一般在生产环境上也会让一个队列绑定多个消费者也就是工作队列模式来减轻压力,提高消息处理效率。

MQ重发消息场景

  1. 消费者未响应ACK,主动关闭频道或连接
  2. 消费者未响应ACK

有序消费消息

场景一:

RabbitMQ采用work Queue模式,此时只会有一个Queue,但是会有多个消费者,同时多个消费者直接是竞争关系,此时就会出现MQ消息乱序的问题。

场景一

解决方案:将3个消费者一个队列改为3个消费者3个队列

生产者根据商品id算出一个hash值然后再对我们的队列的个数取余,就可以让相同id的所有操作压在同一个队列,并且每一个队列都只有一个消费者,此时就不会出现乱序的情况。

场景二

场景二:

当RabbitMQ采用简单队列模式的时候,如果消费者采用多线程的方式来加速消息的处理,此时也会出现消息乱序的问题。

场景二

解决方案:增加一个内存队列,一个线程执行一个内存队列

消费者拉取消息,然后根据id算出一个hash值后,把同id的商品压到同一个内存队列,让同一个线程去处理,此时就保证了有序性。

场景二

重复消费

为防止消息在消费端丢失,会采用手动回复MQ的方式来解决,同时也引出了一个问题,消费者处理消息成功,手动回复MQ时由于网络不稳定,断开连接,导致MQ没有收到消费者回复的消息,那么该条消息还会保存在MQ消息队列,由于MQ的消息重发机制,会重新把该条消息发给和该队列绑定的消费者处理,这样就会导致消息重复消费。而有些操作是不允许重复消费的,比如下单,减库存,扣款等操作。

MQ重发消息场景:

  1. 消费者未响应ACK,主动关闭频道或连接
  2. 消费者未响应ACK,消费者服务挂掉

解决方案:

如果消费者的业务是幕等操作(同一个操作执行多次,结果不变)就算重复消费也没问题,可以不做处理,如果不支持幂等操作,如:下单、减库存、扣款等,那么可以在消费者端每次消费成功后将该消息id保存到数据库,每次消费前查询该消息id,如果该条消息id已经存在,那么表示已经消费过就不再消费,否则就消费。本方案采用redis存储消息id,因为redis是单线程的,并且性能也非常好,提供了很多原子性的命令,本方案使用setnx命令存储消息id。

说明:setnx(key,value):如果key不存在则插入成功返回1,如果key存在,则不进行任何操作,返回0.

最后更新: 2020年08月22日 20:06

原始链接: http://ligangit.com/2020/08/22/RabbitMQ-问题/

× 请我吃糖~
打赏二维码