拓展面试题之-rabbitmq面试题

发布于:2025-07-22 ⋅ 阅读:(13) ⋅ 点赞:(0)

1RabbitMQ的使用场景?【牵涉到很多设计思想,有些主观题可能会和这个有关】
1.解耦,比如微服务中可以不同服务之间的消息通信

解耦系统,对于新增的功能可以单独写模块扩展,比如用户确认评价之后,新增了给用户返积分的功能,这个 时候不用在业务代码里添加新增积分的功能,只需要把新增积分的接口订阅确认评价的消息队列即可,后面再 添加任何功能只需要订阅对应的消息队列即可。

2.异步,将消息写入消息队列,非必要的业务逻辑以异步的方式运行,加快响应速度 3.削峰,并发量大的时候,所有的请求直接怼到数据库,造成数据库连接异常 4.广播:基于Pub/Sub实现一对多通信 5.延迟信息处理,比如 10 分钟之后给下单未付款的用户发送邮件提醒。

2如何保证RabbitMQ不被重复消费?

答:先说为什么会重复消费:正常情况下,消费者在消费消息的时候,消费完毕后,会发送一个确认消息给消息队 列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除;
但是因为网络传输等等故障,确认信息没有传送到消息队列,导致消息队列不知道自己已经消费过该消息了,再次将 消息分发给其他的消费者。
针对以上问题,一个解决思路是:保证消息的唯一性,就算是多次传输,不要让消息的多次消费带来影响;保证消息 等幂性;
比如:在写入消息队列的数据做唯一标示,消费消息时,根据唯一标识判断是否消费过;

3如何保证RabbitMQ消息的可靠传输?

1、发送方确认模式: 将信道设置成confirm模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的ID。 一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息唯一ID)。 如果RabbitMQ发生内部错误从而导致消息丢失,会发送一条nack(not
acknowledged,未确认)消息。 发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。

2、接收方确认机制 接收方消息确认机制:消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,RabbitMQ才能安全地把消息从队列中删除。 这里并没有用到超时机制,
RabbitMQ仅通过Consumer的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ给 了Consumer足够长的时间来处理消息。保证数据的最终一致性; 下面罗列几种特殊情况: 如果消费者接收到消
息,在确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被分发,然后重新分发给下一个订阅的消费者。
(可能存在消息重复消费的隐患,需要去重) 如果消费者接收到消息却没有确认消息,连接也未断开,则RabbitMQ 认为该消费者繁忙,将不会给该消费者分发更多的消息。

4如何保证RabbitMQ的高可用?
采用镜像集群

5rabbitmq如何保证消息的顺序性?
1、【这条是主要的】生产的消息,必须保证在投递到同一个队列,且消费者只能有一个。防止多个消费者乱序。
2、并且发送的时候,不要多线程等并发发送,要同步方式发送。防止多线程乱序发送。
3、发送完后要采用confirm确认机制。确认发送成功了,才进行下一条发送。否则程序就执行中断进程,为了防止 当前消息发送失败,然后下一条又开始发送并且发送成功。

6rabbitmq如何提高消息的消费速率?
1、增加消费者机器
2、优化代码、带宽等等其它设施

7rabbitmq有哪几种路由方式?【知识概念】
direct(默认方式):最基础最简单的模式,发送方把消息发送给订阅方,如果有多个订阅者,默认采取轮询的方式 进行消息发送。
headers:与 direct 类似,只是性能很差,此类型几乎用不到。fanout:分发模式,把消费分发给所有订阅者。 topic:匹配订阅模式,使用正则匹配到消息队列,能匹配到的都能接收到。

详细解释见课件资料文件《资料-rabbitmq四种交换机类型详解》

8rabbitmq交换机与队列、队列与消费者的绑定关系是什么样的?多个消费者监听一个队列 时,消息会重复消费吗?
(1)交换机与队列、队列与消费者的绑定关系都是多对多。

(2)当一个队列有多个消费者时,会采用轮询方式平均分发,不会重复消费。

9rabbitmq的vhost 是什么?起什么作用?
vhost 可以理解为虚拟 broker ,即 mini-RabbitMQ server 。其内部均含有独立的 queue 、 exchange 和
binding 等,但最最重要的是,其拥有独立的权限系统,可以做到 vhost 范围的用户控制。当然,从 RabbitMQ
的全局角度, vhost 可以作为不同权限隔离的手段(一个典型的例子就是不同的应用可以跑在不同的 vhost 中)。

10rabbitmq消息基于什么传输?
RabbitMQ使用信道的方式来传输数据。信道是建立在真实的TCP连接内的虚拟连接,且每条TCP连接上的信道数量 没有限制
channal设计的目的:TCP复用

补充:
首先客户端必须连接到 RabbitMQ 服务器才能发布和消费消息,客户端和 rabbit server 之间会创建一个 tcp
连接,一旦 tcp 打开并通过了认证(认证就是你发送给 rabbit 服务器的用户名和密码),你的客户端和
RabbitMQ 就创建了一条 amqp 信道(channel),信道是创建在“真实” tcp 上的虚拟连接,amqp 命令都是通过信道发送出去的,每个信道都会有一个唯一的 id,不论是发布消息,订阅队列都是通过这个信道完成的。

11rabbitmq死信队列和延迟队列的使用?
死信消息:
消息被拒绝(Basic.Reject或Basic.Nack)并且设置 requeue 参数的值为 false 消息过期了 队列达到最大的长度过期消息:
在 rabbitmq 中存在2种方可设置消息的过期时间,第一种通过对队列进行设置,这种设置后,该队列中所有的消息都存在相同的过期时间,第二种通过对消息本身进行设置,那么每条消息的过期时间都不一样。如果同时使用这2种 方法,那么以过期时间小的那个数值为准。当消息达到过期时间还没有被消费,那么那个消息就成为了一个 死信 消息。
队列设置:在队列申明的时候使用 x-message-ttl 参数,单位为 毫秒单个消息设置:是设置消息属性的 expiration 参数的值,单位为 毫秒
延时队列:在rabbitmq中不存在延时队列,但是我们可以通过设置消息的过期时间和死信队列来模拟出延时队列。 消费者监听死信交换器绑定的队列,而不要监听消息发送的队列。

12使用了消息队列会有什么缺点?
1.增加了额外的消息队列技术栈,需要维护,该技术栈如果挂了,也会带来额外的成本
2.系统复杂性增加:要多考虑很多方面的问题,比如一致性问题、如何保证消息不被重复消费,如何保证保证消息可靠 传输。因此,需要考虑的东西更多,系统复杂性增大。

13rabbitmq多个消费者监听一个队列时,消息如何分发?
轮询: 默认的策略,消费者轮流,平均地接收消息
公平分发: 根据消费者的能力来分发消息,给空闲的消费者发送更多消息
//当消费者有x条消息没有响应ACK时,不再给这个消费者发送消息

14消息在什么时候会变成死信?
消息拒绝并且没有设置重新入队消息过期
消息堆积,并且队列达到最大长度,先入队的消息会变成DL

15RabbitMQ如何实现延时队列?
利用TTL(队列的消息存活时间或者消息存活时间),加上死信交换机

16RabbitMQ如何解决消息幂等性?

17RabbitMQ的集群模式和集群节点类型?
普通模式:默认模式,以两个节点(rabbit01,rabbit02)为例来进行说明,对于Queue来说,消息实体只存在于其 中一个节点rabbit01(或者rabbit02),rabbit01和rabbit02两个节点仅有相同的元数据,即队列结构。当消息进入
rabbit01节点的Queue后,consumer从rabbit02节点消费时,RabbitMQ会临时在rabbit01,rabbit02间进行消息 传输,把A中的消息实体取出并经过B发送给consumer,所以consumer应尽量连接每一个节点,从中取消息。即对 于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连rabbit01或rabbit02,出口总在
rabbit01,会产生瓶颈。当rabbit01节点故障后,rabbit02节点无法取到rabbit01节点中还未消费的消息实体。
镜像模式:把需要的队列做成镜像队列,存在与多个节点属于RabibitMQ的HA方案,该模式解决了普通模式中的问 题,其实质和普通模式不同之处在于,消息体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取,该模式 带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽 将会被这种同步通讯大大消耗掉,所以在对可靠性要求比较高的场合中适用
节点分为内存节点(保存状态到内存,但持久化的队列和消息还是会保存到磁盘),磁盘节点(保存状态到内存和磁 盘),一个集群中至少需要一个磁盘节点

18如何自动删除长时间没有消费的消息
1、设置队列为TTL
2、设置每条消息的过期时间

19RabbitMQ集群怎么避免重启后消息丢失?
把消息持久化磁盘,保证服务器重启消息不丢失。 每个集群中至少有一个物理磁盘,保证消息落入磁盘。
【想学rabbitmq集群,星火老师srm的rabbitmq章节】
20RabbitMQ 对集群节点停止顺序有要求吗?
RabbitMQ 对集群的停止的顺序是有要求的,应该先关闭内存节点,最后再关闭磁盘节点。如果顺序恰好相反的话, 可能会造成消息的丢失。

21RabbitMQ 有哪些重要的组件?
RabbitMQ 中重要的角色有:生产者、消费者和代理:
生产者:消息的创建者,负责创建和推送数据到消息服务器; 消费者:消息的接收方,用于处理数据和确认消息;
代理:就是 RabbitMQ 本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。

22消息的持久化是如何实现的
(1)exchange持久化,在声明时指定durable => 1 (2)queue持久化,在声明时指定durable => 1 (3)消息持久化,在投递时指定delivery_mode => 2(1是非持久化)

23如何保证消息不丢失
生产者开启事务或者发送方确认机制,交换机、队列和消息全部设置持久化,消费者开启消费确认机制

24RabbitMq中的概念及解释
Broker:简单来说就是消息队列服务器实体。 Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。Queue:消息队列载体,每个消息都会被投入到一个或多个队列。 Binding:绑定,它的作用就是把exchange和
queue按照路由规则绑定起来。 Routing Key:路由关键字,exchange根据这个关键字进行消息投递。 vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。 producer:消息生产者,就是投递消息的程序。 consumer:消息消费者,就是接受消息的程序。 channel:消息通道,在客户端的每个连接里,可建立多个
channel,每个channel代表一个会话任务。
消息队列的一个典型使用过程大概如下:
(1)客户端连接到消息队列服务器,打开一个channel。 (2)客户端声明一个exchange,并设置相关属性。
(3)客户端声明一个queue,并设置相关属性。 (4)客户端使用routing key,在exchange和queue之间建立好绑定关系。 (5)客户端投递消息到exchange。
exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列 里。

由上可以看出: 消费端:需要将queue与exchange绑定,通过routing_key来实现规则绑定。 生产端:将消息发送到exchange时附加上 routing_key 即可以了,exchange会根据上面的规则来决定放在哪个queue里。(要考虑Exchange Type设置)

25RabbitMq消息什么时候需要持久化?
根据 官方博文 的介绍,RabbitMQ在两种情况下会将消息写入磁盘:
1.消息本身在publish的时候就要求消息写入磁盘;
2.内存紧张,需要将部分内存中的消息转移到磁盘;

26RabbitMq消息什么时候会刷到磁盘?
1.写入文件前会有一个Buffer,大小为1M(1048576),数据在写入文件时,首先会写入到这个Buffer,如果
Buffer已满,则会将Buffer写入到文件(未必刷到磁盘);
2.有个固定的刷盘时间:25ms,也就是不管Buffer满不满,每隔25ms,Buffer里的数据及未刷新到磁盘的文件 内容必定会刷到磁盘;
3.每次消息写入后,如果没有后续写入请求,则会直接将已写入的消息刷到磁盘:使用Erlang的receive x after 0
来实现,只要进程的信箱里没有消息,则产生一个timeout消息,而timeout会触发刷盘操作。

27如果让你写一个消息队列,该如何进行架构设计?说一下你的思路。

其实聊到这个问题,一般面试官要考察两块:
你有没有对某一个消息队列做过较为深入的原理的了解,或者从整体了解把握住一个消息队列的架构原理。 看看你的设计能力,给你一个常见的系统,就是消息队列系统,看看你能不能从全局把握一下整体架构设计, 给出一些关键点出来。
说实话,问类似问题的时候,大部分人基本都会蒙,因为平时从来没有思考过类似的问题,大多数人就是平时埋头 用,从来不去思考背后的一些东西

比如说这个消息队列系统,我们从以下几个角度来考虑一下:
首先这个 mq 得支持可伸缩性吧,就是需要的时候快速扩容,就可以增加吞吐量和容量,那怎么搞?设计个分 布式的系统呗,参照一下 kafka 的设计理念,broker -> topic -> partition,每个 partition 放一个机器,就存一部分数据。如果现在资源不够了,简单啊,给 topic 增加 partition,然后做数据迁移,增加机器,不就可以存放更多数据,提供更高的吞吐量了?
其次你得考虑一下这个 mq 的数据要不要落地磁盘吧?那肯定要了,落磁盘才能保证别进程挂了数据就丢了。那落磁盘的时候怎么落啊?顺序写,这样就没有磁盘随机读写的寻址开销,磁盘顺序读写的性能是很高的,这 就是 kafka 的思路。
其次你考虑一下你的 mq 的可用性啊?这个事儿,具体参考之前可用性那个环节讲解的 kafka 的高可用保障机制。多副本 -> leader & follower -> broker 挂了重新选举 leader 即可对外服务。
能不能支持数据 0 丢失啊?可以的,参考我们之前说的那个 kafka 数据零丢失方案。


网站公告

今日签到

点亮在社区的每一天
去签到