持续输出面试题之RabbitMQ篇

开篇介绍

你们好,我是Java最全面试题库的提裤姐,今天这篇是中间件面试题系列的第一篇,主要总结了RabbitMQ相关的面试题;在后续,会沿着第一篇开篇的知识线路一直总结下去,作到日更!若是我能作到百日百更,但愿你也能够跟着百日百刷,一百天养成一个好习惯。面试

什么是RabbitMQ?为何使用RabbitMQ?有什么好处?

RabbitMQ是一款开源的,Erlang编写的,基于AMQP协议的,消息中间件;
能够用它来:解耦异步削峰服务器

  • 优势:解耦、异步、削峰;
  • 缺点:下降了系统的稳定性:系统中使用了消息队列,若是消息队列挂了,那么系统也会挂掉。所以,系统可用性会下降;

加入了消息队列,要多考虑不少方面的问题,好比:一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等。所以,须要考虑的东西更多,复杂性增大。网络

RabbitMQ基本概念有哪些?

  • Broker: 消息队列服务器实体
  • Exchange: 消息交换机,它指定消息按特定规则,路由到哪一个队列
  • Queue: 消息队列载体,每一个消息都会被投入到一个或多个队列
  • Binding: 绑定,它的做用就是把exchange和queue按照路由规则绑定起来
  • Routing Key: 路由关键字,exchange根据这个关键字进行消息投递
  • VHost: vhost 能够理解为虚拟 broker ,即 mini-RabbitMQ server。其内部均含有独立的 queue、exchange 和 binding 等,拥有独立的权限系统,能够作到 vhost 范围的用户控制。
  • Producer: 消息生产者
  • Consumer: 消息消费者
  • Channel: 消息通道,在客户端的每一个链接里,可创建多个channel,每一个channel表明一个会话任务

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

正常状况下,消费者在消费消息的时候,消费完毕后,会发送一个确认消息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除;异步

可是由于网络传输等等故障,确认信息没有传送到消息队列,致使消息队列不知道本身已经消费过该消息了,再次将消息分发给其余的消费者。操作系统

解决思路:
保证消息的惟一性,就算是屡次传输,不要让消息的屡次消费带来影响;保证消息等幂性;
好比:在写入消息队列的数据作惟一标识,消费消息时,根据惟一标识判断是否消费过;线程

RabbitMQ 概念里的 channel、exchange 和 queue 是逻辑概念,仍是对应着进程实体?分别起什么做用?

queue 具备本身的 erlang 进程;
exchange 内部实现为保存 binding 关系的查找表;
channel 是实际进行路由工做的实体,即负责按照 routing_key 将 message 投递给 queue 。code

由 AMQP 协议描述可知,channel 是真实 TCP 链接之上的虚拟链接,全部 AMQP 命令都是经过 channel 发送的,且每个 channel 有惟一的 ID。一个 channel 只能被单独一个操做系统线程使用,故投递到特定 channel 上的 message 是有顺序的。但一个操做系统线程上容许使用多个 channel 。server

rabbitmq 消息是如何路由的?

从概念上来讲,消息路由必须有三部分:交换器、路由、绑定。中间件

生产者把消息发布到交换器上;绑定决定了消息如何从路由器路由到特定的队列;消息最终到达队列,并被消费者接收。
消息发布到交换器时,消息将拥有一个路由键(routing key),在消息建立时设定。
经过队列路由键,能够把队列绑定到交换器上。
消息到达交换器后,RabbitMQ会将消息的路由键与队列的路由键进行匹配(针对不一样的交换器有不一样的路由规则)。若是可以匹配到队列,则消息会投递到相应队列中;若是不能匹配到任何队列,消息将进入 “黑洞”。rabbitmq

经常使用的交换器主要分为一下三种:

  • direct:若是路由键彻底匹配,消息就被投递到相应的队列
  • fanout:若是交换器收到消息,将会广播到全部绑定的队列上
  • topic:可使来自不一样源头的消息可以到达同一个队列。 使用topic交换器时,可使用通配符,好比:“*” 匹配特定位置的任意文本, “.” 把路由键分为了几部分,“#” 匹配全部规则等。
特别注意:发往topic交换器的消息不能随意的设置选择键(routing_key),必须是由"."隔开的一系列的标识符组成。

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

消息不可靠的状况多是消息丢失,劫持等缘由
丢失又分为:

  • 生产者丢失消息
  • 消息列表丢失消息
  • 消费者丢失消息

生产者丢失消息:
从生产者弄丢数据这个角度来看,RabbitMQ提供transaction机制confirm模式来确保生产者不丢消息;

  • transaction机制:发送消息前,开启事务(channel.txSelect()),而后发送消息,若是发送过程当中出现什么异常,事务就会回滚(channel.txRollback()),若是发送成功则提交事务(channel.txCommit())。
  • confirm模式(用的居多):一旦channel进入confirm模式,全部在该信道上发布的消息都将会被指派一个惟一的ID(从1开始),一旦消息被投递到全部匹配的队列以后; RabbitMQ就会发送一个ACK给生产者(包含消息的惟一ID),这就使得生产者知道消息已经正确到达目的队列了;

若是RabbitMQ没能处理该消息,则会发送一个Nack消息给你,你能够进行重试操做。

消息队列丢数据:
消息持久化,处理消息队列丢数据的状况,通常是开启持久化磁盘的配置:
将队列的持久化标识durable设置为true,则表明是一个持久的队列 发送消息的时候将 deliveryMode=2 这样设置之后,即便RabbitMQ挂了,重启后也能恢复数据

消费者丢失消息:
消费者丢数据通常是由于采用了自动确认消息模式,改成手动确认消息
消费者在收到消息以后,处理消息以前,会自动回复RabbitMQ已收到消息; 若是这时处理消息失败,就会丢失该消息;
解决方案:处理消息成功后,手动回复确认消息。

如何保证RabbitMQ消息的顺序性?

一、单线程消费保证消息的顺序性;
二、对消息进行编号,消费者处理消息是根据编号处理消息;

死信队列和延迟队如何使用?

死信队列:
死信,顾名思义就是没法被消费的消息,字面意思能够这样理解,通常来讲,producer将消息投递到broker或者直接到queue里了,consumer从queue取出消息进行消费,但某些时候因为特定的缘由致使queue中的某些消息没法被消费,这样的消息若是没有后续的处理,就变成了死信,有死信,天然就有了死信队列;

死信消息:
一、消息被拒绝(Basic.RejectBasic.Nack)而且设置 requeue 参数的值为 false
二、消息过时了
三、队列达到最大的长度

过时消息:
在 rabbitmq 中存在2种方可设置消息的过时时间,

  • 第一种经过对队列进行设置,这种设置后,该队列中全部的消息都存在相同的过时时间,
  • 第二种经过对消息自己进行设置,那么每条消息的过时时间都不同。

若是同时使用这2种方法,那么以过时时间小的那个数值为准。当消息达到过时时间尚未被消费,那么那个消息就成为了一个 死信 消息。

队列设置:在队列申明的时候使用 x-message-ttl 参数,单位为 毫秒
单个消息设置:是设置消息属性的 expiration 参数的值,单位为 毫秒

延时队列:在rabbitmq中不存在延时队列,可是咱们能够经过设置消息的过时时间和死信队列来模拟出延时队列。消费者监听死信交换器绑定的队列,而不要监听消息发送的队列。

相关文章
相关标签/搜索