RabbitMQ面试题

相关术语

Producer(生产者)

也就是消息的上游, 一个系统A 产生了一些信息.
可能需要另外一个系统B 去处理.
那么, 系统A 就是一个 Producer

Consumer(消费者)
一个系统B, 需要处理另一个系统A 的消息.
那么 系统B就是一个 Consumer

注意: 一个系统可以是Producer,也可以是Consumer.

Broker
Broker 就是mq, 消息队列中间件.
它去协调在两个系统之间的消息. 尽可能地让消息不丢失,不重复。

在RabbitMQ中,生产者、队列和消费者到底是怎么联系起来的呢?消息分发又有哪些策略呢?

请看这里

1、消息堆积

当生产消息的速度长时间,远远大于消费的速度时,就会造成消息堆积

  • 消息堆积的影响
    • 可能导致新的消息无法进入队列
    • 可能导致旧消息无法删除
    • 消息等待消费的时间过长,超出了业务容忍的范围
  • 产生消息堆积的情况
    • 生产者突然大量发布消息
    • 消费者消费失败
    • 消费者性能出现瓶颈
    • 消费者挂掉
  • 解决办法
    • 排查消费者的消费性能瓶颈
    • 增加消费者的多线程处理
    • 部署多个消费者

2、消息丢失

在实际的生产环境中有可能出现一条消息因为一些原因丢失,,导致消息没有消费成功,从而造成数据不一致的问题,造成验证影响。比如:在一个商城的下达业务中,需要生成订单信息和扣减库存的两个动作,入股使用MQ来实现的话,那么在订单下单成功后需要发送一条消息到库存进行减扣操作,如果在此过程中,一条消息因为某些原因丢失,那么就会出现下单成功但是库存没有扣减,从而导致超卖的问题。

消息丢失的场景分为:消息在生产者丢失,消息在RabbitMQ丢失,消息在消费者丢失

2.1消息在生产者丢失

消息生产者发送消息成功,但是MQ没有收到该消息,消息在从生产者传输到MQ的过程中丢失,一般是由于网络不稳定的缘故。

解决方案

采用RabbitMQ的消息确机制,当消息成功被MQ接收时,会给生产者发送一个确认消息,表示接收成功。RabbitMQ发送方消息确认模式有以下三种:普通确认模式,批量确认模式,异步监听确认模式。最常用的是异步监听确认模式。

说明

异步监听确认模式(confirm回调机制),可以实现边发送消息边进行确认,不影响主线程的任务执行

2.2消息在RabbitMQ丢失

消息成功发送到MQ,消息还没被消费却在MQ中消失,比如MQ服务器宕机后者重启会出现这种情况

解决方案

持续化交换机,队列,消息,确保MQ服务器重启时依然能从磁盘恢复对应的交换机,队里和消息。springboot整合后默认开启了交换机,队列,消息的持久化,所以不修改任何设置就可以保证消息不在RabbitMQ中丢失。

2.3消息在消费者丢失

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

解决方案

设置手动恢复MQ服务器,当消费者服务出现异常或者服务宕机时,MQ服务器不会删除该消息,而是把消息重发给绑定该队列的消费者,如果该队列只绑定了一个消费者,那么该消息会一直保存在MQ服务器,知道消费者能正常消费为止。

MQ消息重发的场景

  • 消费者未响应ACK,主动关闭频道或者链接
  • 消费者为相应ACK,消费者服务挂掉

3、有序消费信息

场景1

当MQ采用work-queue模式时,此时只有一个queue,但是会有多个consumer,同时多个consumer是直接竞争关系,此时就会出现MQ消息乱序的问题
在这里插入图片描述

解决方案

在这里插入图片描述

场景2

当MQ采用简单队列模式的时候,如果消费者采用多线程的方式来加速消息的处理,此时也会出现消息乱序的问题
在这里插入图片描述

解决方案

在这里插入图片描述

4、重复消费

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

MQ消息重发的场景:

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

解决方案

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值