RabbitMQ面试题
RabbitMQ的使用场景
- 流量消锋
可以通过指定springboot配置参数设置从broker
中拉取的消息数量,减少spring
与rabbitmq
之间的网络交互,
以及指定监听器的并发请求处理数量,对流量进行消锋
- 应用解耦
通过rabbitmq
间接调用其他服务,防止服务间调用的强耦合
- 异步处理
部分业务处理比较耗时,可以通过rabbitmq
进行异步处理
RabbitMQ
是什么?
RabbitMQ
是一个消息中间件,用于接收、存储、转发消息
RabbitMQ
架构
RabbitMQ
主要由以下几部分组成:
broker
:相当于rabbitmq
的服务器virtual host
:虚拟机,相当于namespace
用于隔离环境exchange
:交换机,用于分发消息,将消息投递到指定队列- queue:队列,用于存储消息
exchange
和queue
之间使用routingkey
进行绑定
-
connecting
:客户端与服务器间的建立物理连接 -
channel
:信道,用于客户端和broker
进行通信
RabbitMQ
工作流程
客户端与服务器建立连接,开启一个信道,向broker
发送消息,消息到达broker后会投递到指定队列,根据消息所携带的routingkey
转发到指定队列,消费者端同样会建立连接,并开启信道,对指定的队列进行监听,如果队列中有消息,则会拉取消息到消费者端进行消费
RabbitMQ
的工作模式有哪些
-
简单模式
生产者和消费者之间直接采用队列进行收发,不引用交换机
-
工作队列模式
生产者和消费者之间仍只是用队列进行收发,有多个消费者,消费者会采用轮询的方式对消息进行消费
-
发布订阅模式(广播模式)
绑定到交换机的每一个队列都能收到消息
-
直接模式
交换机会根据不同的
routingkey
将消息投递到不同的队列中 -
主题模式
要求
routingkey
采用单词组组成,中间使用.
进行分割命名规范:
*
代表一个单词#
代表0~n
个单词交换机会根据
key
进行模糊查找队列 -
rpc模式
:参考官网,了解即可
RabbitMQ
消息丢失的情况有哪些
-
produce
向broker
发送消息丢失网络/代码问题,消息未发送成功
-
rabbitmq server
存储消息丢失消息没有持久化,重启丢失
-
rabbitmq server
向consumer
分发消息丢失消费时未来的及处理消息服务器宕机
处理代码异常
RabbitMQ
如何保障消息不丢失
-
开启消息与队列的持久化
-
开启发布确认
- 消息到达交换机:
ConfirmCallback
包含失败原因,失败内容等 - 交换机向队列投递失败:
ReturnsCallback
消息会回退
- 消息到达交换机:
-
开启手动应答模式
如何100%
保障消息发送成功
如果要100%
保障则可以采用消息补偿架构设计
讲解
RabbitMQ
的消息确认机制有哪些
- 自动应答 默认
- 手动应答
- 批量应答
什么是死信队列
用于存储一些由于特殊原因导致无法消费的消息的队列称为私信队列,这些消息一般需要进行手动处理
造成消息变为死信消息的原因有哪些?
- 消息
TTL
过期 - 队列到达最大长度
- 消息被拒接,并且
requeue
为false
如何实现延迟队列?
RabbitMQ
没有默认的延迟队列供使用,需要使用普通队列设置ttl
+死信队列的方式实现延迟队列,当消息到达ttl
的时间后就会自动进入死信队列,消费者可以对死信队列进行监听消费
如何实现不公平分发?
RabbitMQ
默认采用轮询的方式将消息分发到消费者,但是通常可能会出现消费者消费速度不一致相差较大的情况,所以可以考虑采用不公平分发
在消费者端设置未确认消息最大数量 basicQoschannel.basicQos(nums);
如何保障消息的幂等性?
MySQL
可以使用乐观锁机制,为需要更新的数据分配一个version
当执行更新语句时相当于执行update table set xxx=xxx where exp1 and version=1
如果被更新后version
会更新为2
Redis
如果数据只是为了缓存到Redis
,这种情况天然幂等
复杂场景可以为消息分配一个全局唯一id
,消费者消费消息时根据这个ID
去redis
当中查询之前是否消费过。如果没有消费过,就进行消费并将这个消息的ID
写入到redis当中。如果已经消费过了,就无需再次消费了
如何保障消息的顺序性
消息顺序错乱场景
- 一个队列对应多个
consumer
- 一个队列对应一个
consumer
,但是采用了多线程进行处理
解决方案
- 对原先的队列拆分为多个,每个队列对应一个消费者,保障队列和消费者之间的一对一
- 在消费者内存中维护多个内存队列,根据关键字从不同的队列中获取消息