步伐员的20大RabbitMQ口试问题及答案

打印 上一主题 下一主题

主题 686|帖子 686|积分 2058

1、什么是 RabbitMQ?为什么使用 RabbitMQ?

RabbitMQ 是一款开源的,Erlang 编写的,基于 AMQP 协议的,消息中间件;
可以用它来:解耦、异步、削峰。
2、RabbitMQ 有什么优缺点?

优点:解耦、异步、削峰;
缺点:低落了系统的稳定性:原来系统运行好好的,现在你非要加入个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性会低落;
增长了系统的复杂性:加入了消息队列,要多思量很多方面的问题,好比:一致性问题、如何保证消息不被重复消耗、如何保证消息可靠性传输等。因此,须要思量的东西更多,复杂性增大。
3.rabbitmq 的使用场景

(1)服务间异步通信
(2)顺序消耗
(3)定时使命
(4)请求削峰
4.RabbitMQ根本概念

Broker: 简单来说就是消息队列服务器实体
Exchange: 消息交换机,它指定消息按什么规则,路由到哪个队列
Queue: 消息队列载体,每个消息都会被投入到一个或多个队列
Binding: 绑定,它的作用就是把exchange和queue按照路由规则绑定起来
Routing Key: 路由关键字,exchange根据这个关键字进行消息投递
VHost: vhost 可以理解为虚拟 broker ,即 mini-RabbitMQ server。其内部均含有独立的 queue、exchange 和 binding 等,但最最重要的是,其拥有独立的权限系统,可以做到 vhost 范围的用户控制。当然,从 RabbitMQ 的全局角度,vhost 可以作为不同权限隔离的手段(一个典范的例子就是不同的应用可以跑在不同的 vhost 中)。
Producer: 消息生产者,就是投递消息的步伐
Consumer: 消息消耗者,就是接受消息的步伐
Channel: 消息通道,在客户端的每个毗连里,可创建多个channel,每个channel代表一个会话使命
由Exchange、Queue、RoutingKey三个才能决定一个从Exchange到Queue的唯一的线路。
5.RabbitMQ 中的 broker 是指什么?cluster 又是指什么?

broker 是指一个或多个 erlang node 的逻辑分组,且 node 上运行着 RabbitMQ 应用步伐。
cluster 是在 broker 的根本之上,增长了 node 之间共享元数据的约束。
6、RabbitMQ 概念里的 channel、exchange 和 queue 是逻辑概念,还是对应着历程实体?分别起什么作用?

Queue 具有本身的 erlang 历程;exchange 内部实现为保存 binding 关系的查找表;channel 是实际进行路由工作的实体,即负责按照 routing_key 将 message 投递给 queue 。由 AMQP 协议描述可知,channel 是真实 TCP 毗连之上的虚拟毗连,所有 AMQP 命令都是通过 channel 发送的,且每一个 channel 有唯一的 ID。一个 channel 只能被单独一个操纵系统线程使用,故投递到特定 channel 上的 message 是有顺序的。但一个操纵系统线程上允许使用多个 channel 。
7 vhost 是什么?起什么作用?

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

由于TCP毗连的创建和销毁开销较大,且并发数受系统资源限定,会造成性能瓶颈。RabbitMQ使用信道的方式来传输数据。信道是创建在真实的TCP毗连内的虚拟毗连,且每条TCP毗连上的信道数量没有限定。
9. 消息如何分发?

若该队列至少有一个消耗者订阅,消息将以循环(round-robin)的方式发送给消耗者。每条消息只会分发给一个订阅的消耗者(前提是消耗者可以或许正常处理消息并进行确认)。
10. 消息怎么路由?

从概念上来说,消息路由必须有三部门:交换器路由绑定。生产者把消息发布到交换器上;绑定决定了消息如何从路由器路由到特定的队列;消息终极到达队列,并被消耗者吸收。
消息发布到交换器时,消息将拥有一个路由键(routing key),在消息创建时设定。
通过队列路由键,可以把队列绑定到交换器上。
消息到达交换器后,RabbitMQ会将消息的路由键与队列的路由键进行匹配(针对不同的交换器有不同的路由规则)。如果可以或许匹配到队列,则消息会投递到相应队列中;如果不能匹配到任何队列,消息将进入 “黑洞”。
常用的交换器主要分为一下三种:


  • direct:如果路由键完全匹配,消息就被投递到相应的队列
  • fanout:如果交换器收到消息,将会广播到所有绑定的队列上
  • topic:可以使来自不同源头的消息可以或许到达同一个队列。使用topic交换器时,可以使用通配符。
    好比:“*” 匹配特定位置的恣意文本, “.” 把路由键分为了几部门,“#” 匹配所有规则等。
    特别注意:发往topic交换器的消息不能随意的设置选择键(routing_key),必须是由"."隔开的一系列的标识符组成。
11. 什么是元数据?元数据分为哪些类型?包括哪些内容?与 cluster 相干的元数据有哪些?元数据是如何保存的?元数据在 cluster 中是如何分布的?

在非 cluster 模式下,元数据主要分为 Queue 元数据(queue 名字和属性等)、Exchange元数据(exchange 名字、类型和属性等)、Binding 元数据(存放路由关系的查找表)、Vhost元数据(vhost 范围内针对前三者的名字空间约束和安全属性设置)。
在 cluster 模式下,还包括 cluster 中 node 位置信息和 node 关系信息。元数据按照 erlang node 的类型确定是仅保存于 RAM 中,还是同时保存在 RAM 和 disk 上。元数据在 cluster 中是全 node 分布的。
12. 在单node 系统和多 node 构成的 cluster 系统中声明 queue、exchange ,以及进行 binding 会有什么不同?

答:当你在单 node 上声明 queue 时,只要该 node 上相干元数据进行了变更,你就会得到 Queue.Declare-ok 回应;而在 cluster 上声明 queue ,则要求 cluster 上的全部 node 都要进行元数据乐成更新,才会得到 Queue.Declare-ok 回应。另外,若 node 类型为 RAM node 则变更的数据仅保存在内存中,若类型为 disk node 则还要变更保存在磁盘上的数据。
死信队列&死信交换器:DLX 全称(Dead-Letter-Exchange),称之为死信交换器,当消息变成一个死信之后,如果这个消息所在的队列存在x-dead-letter-exchange参数,那么它会被发送到x-dead-letter-exchange对应值的交换器上,这个交换器就称之为死信交换器,与这个死信交换器绑定的队列就是死信队列。
13. 如何确保消息正确地发送至RabbitMQ?

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

吸收方消息确认机制:消耗者吸收每一条消息后都必须进行确认(消息吸收和消息确认是两个不同操纵)。只有消耗者确认了消息,RabbitMQ才能安全地把消息从队列中删除。这里并没有用到超机遇制,RabbitMQ仅通过Consumer的毗连停止来确认是否须要重新发送消息。也就是说,只要毗连不停止,RabbitMQ给了Consumer足够长的时间来处理消息。
下面罗列几种特别情况:


  • 如果消耗者吸收到消息,在确认之前断开了毗连或取消订阅,RabbitMQ会以为消息没有被分发,然后重新分发给下一个订阅的消耗者。(可能存在消息重复消耗的隐患,须要根据bizId去重)
  • 如果消耗者吸收到消息却没有确认消息,毗连也未断开,则RabbitMQ以为该消耗者繁忙,将不会给该消耗者分发更多的消息。
15、如何保证 RabbitMQ 不被重复消耗?

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

消息不可靠的情况可能是消息丢失,挟制等原因;
丢失又分为:生产者丢失消息、消息列表丢失消息、消耗者丢失消息;
生产者丢失消息:从生产者弄丢数据这个角度来看,RabbitMQ 提供 transaction 和 confirm 模式来确保生产者不丢消息;
transaction 机制就是说:发送消息前,开启事务(channel.txSelect()), 然后发送消息,如果发送过程中出现什么非常,事务就会回滚(channel.txRollback()), 如果发送乐成则提交事务(channel.txCommit())。然而,这种方式有个缺点:吞吐量下降;
confirm 模式用的居多:一旦 channel 进入 confirm 模式,所有在该信道上发布的消息都将会被指派一个唯一的 ID(从 1 开始),一旦消息被投递到所有匹配的队列之后;
rabbitMQ 就会发送一个 ACK 给生产者(包含消息的唯一 ID),这就使得生产者知道消息已经正确到达目的队列了;
如果 rabbitMQ 没能处理该消息,则会发送一个 Nack 消息给你,你可以进行重试操纵。
消息队列丢数据:消息长期化。
处理消息队列丢数据的情况,一般是开启长期化磁盘的设置。
这个长期化设置可以和 confirm 机制共同使用,你可以在消息长期化磁盘后,再给生产者发送一个 Ack 信号。
如许,如果消息长期化磁盘之前,rabbitMQ 阵亡了,那么生产者收不到 Ack 信号,生产者会主动重发。
那么如何长期化呢?
这里顺便说一下吧,着实也很容易,就下面两步

  • 将 queue 的长期化标识 durable 设置为 true, 则代表是一个长期的队列
  • 发送消息的时候将 deliveryMode=2
如许设置以后,纵然 rabbitMQ 挂了,重启后也能恢复数据
消耗者丢失消息:消耗者丢数据一般是因为采用了主动确认消息模式,改为手动确认消息即可!
消耗者在收到消息之后,处理消息之前,会主动复兴 RabbitMQ 已收到消息;
如果这时处理消息失败,就会丢失该消息;
解决方案:处理消息乐成后,手动复兴确认消息。
17、如何保证 RabbitMQ 消息的顺序性?

单线程消耗保证消息的顺序性;对消息进行编号,消耗者处理消息是根据编号处理消息;
18. 死信队列和耽误队列的使用?

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

有了以上的根本知识,我们完成以下需求:
需求:用户在系统中创建一个订单,如果超过期间用户没有进行支付,那么主动取消订单。
分析:
1、上面这个情况,我们就得当使用延时队列来实现,那么延时队列如何创建
2、延时队列可以由 过期消息+死信队列 来时间
3、过期消息通过队列中设置 x-message-ttl 参数实现
4、死信队列通过在队列申明时,给队列设置 x-dead-letter-exchange 参数,然后另外申明一个队列绑定x-dead-letter-exchange对应的交换器。
19. 使用了消息队列会有什么缺点?

1.系统可用性低落:你想啊,原来其他系统只要运行好好的,那你的系统就是正常的。现在你非要加个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性低落
2.系统复杂性增长:要多思量很多方面的问题,好比一致性问题、如何保证消息不被重复消耗,如何保证保证消息可靠传输。因此,须要思量的东西更多,系统复杂性增大。
20. 多个消耗者监听一个队列时,消息如何分发?



  • 轮询: 默认的策略,消耗者轮流,均匀地吸收消息
  • 公平分发: 根据消耗者的能力来分发消息,给空闲的消耗者发送更多消息
当消耗者有x条消息没有响应ACK时,不再给这个消耗者发送消息
  1. channel.basicQos(int x)
复制代码
  不知道你是喜欢好天还是雨天,反正我喜欢你的每一天

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

麻花痒

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表