定制开发RabbitMQ常见面试题及答案 90道(2021版)

定制开发面试题以及答案整理【最新版】RabbitMQ定制开发高级定制开发定制开发面试题大全(2021版),定制开发发现网上很多RabbitMQ定制开发面试题都没有答案,定制开发所以花了很长时间搜集,本套RabbitMQ面试题大全

如果不背 RabbitMQ 定制开发面试题的答案,定制开发肯定面试会挂!

这套RabbitMQ面试题大全,定制开发希望对大家有帮助哈~

1、 定制开发消息生产者将消息发送定制开发给交换机按照路由判断,定制开发路由是字符串(info) 定制开发当前产生的消息携带路由字符(定制开发对象的方法),定制开发交换机根据路由的key,定制开发只能匹配上路由key定制开发对应的消息队列,定制开发对应的消费者才能消费消息;

2、 定制开发根据业务功能定义路由字符串

3、 定制开发从系统的代码逻辑中获定制开发取对应的功能字符串,定制开发将消息任务扔到对应的队列中。

4、 业务场景:error 通知;EXCEPTION;定制开发错误通知的功能;定制开发传统意义的错误通知;客户通知;利用key路由,定制开发可以将程序中的错误封定制开发装成消息传入到消息队列中,定制开发开发者可以自定义消费者,定制开发实时接收错误;

定制开发消息提供方->路由->定制开发一至多个队列消息发布定制开发到交换器时,定制开发消息将拥有一个路由键(routing key),定制开发在消息创建时设定。定制开发通过队列路由键,定制开发可以把队列绑定到交换器上。定制开发消息到达交换器后,RabbitMQ 定制开发会将消息的路由键与队定制开发列的路由键进行匹配(定制开发针对不同的交换器有不定制开发同的路由规则);

定制开发常用的交换器主要分为一下三种:

1、 fanout:定制开发如果交换器收到消息,定制开发将会广播到所有绑定的队列上

2、 direct:定制开发如果路由键完全匹配,定制开发消息就被投递到相应的队列

3、 topic:定制开发可以使来自不同源头的定制开发消息能够到达同一个队列。 使用 topic 交换器时,定制开发可以使用通配符

1、 定制开发每个消费者监听自己的队列;

2、 定制开发生产者将消息发给broker,定制开发由交换机将消息转发到定制开发绑定此交换机的每个队列,定制开发每个绑定交换机的队列定制开发都将接收到消息。

不能。第一,定制开发你无法控制所创建的 queue 定制开发实际分布在 cluster 里的哪个 node 上(一般使用 HAProxy + cluster 定制开发模型时都是这样),定制开发这可能会导致各种跨地定制开发域访问时的常见问题;第二,Erlang 的 OTP 定制开发通信框架对延迟的容忍度有限,定制开发这可能会触发各种超时,定制开发导致业务疲于处理;第三,定制开发在广域网上的连接失效定制开发问题将导致经典的“脑裂”问题,而RabbitMQ 定制开发目前无法处理(定制开发该问题主要是说 Mnesia)。

1、 Broker:定制开发简单来说就是消息队列定制开发服务器实体

2、 Exchange:定制开发消息交换机,它指定消息按什么规则,路由到哪个队列

3、 Queue:消息队列载体,每个消息都会被投入到一个或多个队列

4、 Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来

5、 Routing Key:路由关键字,exchange根据这个关键字进行消息投递

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

7、 Producer:消息生产者,就是投递消息的程序

8、 Consumer:消息消费者,就是接受消息的程序

9、 Channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务

ExchangeQueueRoutingKey三个才能决定一个从Exchange到Queue的唯一的线路。

blackholed 问题是指,向 exchange 投递了 message ,而由于各种原因导致该message 丢失,但发送者却不知道。可导致 blackholed 的情况:1.向未绑定 queue 的exchange 发送 message;2.exchange 以 binding_key key_A 绑定了 queue queue_A,但向该 exchange 发送 message 使用的 routing_key 却是 key_B。

消费消息,也就是接收消息的一方。

消费者连接到RabbitMQ服务器,并订阅到队列上。消费消息时只消费消息体,丢弃标签。

1、 若该队列至少有一个消费者订阅,消息将以循环(round-robin)的方式发送给消费者。每条消息只会分发给一个订阅的消费者(前提是消费者能够正常处理消息并进行确认)。

2、 通过路由可实现多消费的功能

该信令可用于 consumer 对收到的 message 进行 reject 。若在该信令中设置

requeue=true,则当 RabbitMQ server 收到该拒绝信令后,会将该 message 重新发送到下一个处于 consume 状态的 consumer 处(理论上仍可能将该消息发送给当前consumer)。若设置 requeue=false ,则 RabbitMQ server 在收到拒绝信令后,将直接将该message 从 queue 中移除。

另外一种移除 queue 中 message 的小技巧是,consumer 回复 Basic.Ack 但不对获取到的message 做任何处理。而 Basic.Nack 是对 Basic.Reject 的扩展,以支持一次拒绝多条 message 的能力。

通过绑定将交换器和队列关联起来,一般会指定一个BindingKey,这样RabbitMq就知道如何正确路由消息到队列了。

消息积压处理办法:临时紧急扩容:

1、 先修复 consumer 的问题,确保其恢复消费速度,然后将现有 cnosumer 都停掉。

2、 新建一个 topic,partition 是原来的 10 倍,临时建立好原先 10 倍的 queue 数量。

3、 然后写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的 10 倍数量的 queue。

4、 接着临时征用 10 倍的机器来部署 consumer,每一批 consumer 消费一个临时 queue 的数据。这种做法相当于是临时将 queue 资源和 consumer 资源扩大 10 倍,以正常的 10 倍速度来消费数据。

5、 等快速消费完积压数据之后,得恢复原先部署的架构,重新用原先的 consumer 机器来消费消息。

6、 MQ中消息失效:假设你用的是 RabbitMQ,RabbtiMQ 是可以设置过期时间的,也就是 TTL。如果消息在 queue 中积压超过一定的时间就会被 RabbitMQ 给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在 mq 里,而是大量的数据会直接搞丢。我们可以采取一个方案,就是批量重导,这个我们之前线上也有类似的场景干过。就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比如大家一起喝咖啡熬夜到晚上12点以后,用户都睡觉了。这个时候我们就开始写程序,将丢失的那批数据,写个临时程序,一点一点的查出来,然后重新灌入 mq 里面去,把白天丢的数据给他补回来。也只能是这样了。假设 1 万个订单积压在 mq 里面,没有处理,其中 1000 个订单都丢了,你只能手动写程序把那 1000 个订单给查出来,手动发到 mq 里去再补一次。

mq消息队列块满了:

如果消息积压在 mq 里,你很长时间都没有处理掉,此时导致 mq 都快写满了,咋办?这个还有别的办法吗?没有,谁让你第一个方案执行的太慢了,你临时写程序,接入数据来消费,消费一个丢弃一个,都不要了,快速消费掉所有的消息。然后走第二个方案,到了晚上再补数据吧。

binding 关系可以表示为 exchange – binding – queue 。从文档中我们知道,若要求投递的 message 能够不丢失,要求 message 本身设置 persistent 属性,要求 exchange和 queue 都设置 durable 属性。

其实这问题可以这么想,若 exchange 或 queue 未设置durable 属性,则在其 crash 之后就会无法恢复,那么即使 message 设置了 persistent 属性,仍然存在 message 虽然能恢复但却无处容身的问题;同理,若 message 本身未设置persistent 属性,则 message 的持久化更无从谈起。

// 通过队列属性设置消息过期时间Map<String, Object> argss = new HashMap<String, Object>();argss.put("x-message-ttl",6000);// 对每条消息设置过期时间AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()    .expiration("10000") // TTL

queue 具有自己的 erlang 进程;exchange 内部实现为保存 binding 关系的查找表;channel 是实际进行路由工作的实体,即负责按照 routing_key 将 message 投递给queue 。由 AMQP 协议描述可知,channel 是真实 TCP 连接之上的虚拟连接,所有AMQP 命令都是通过 channel 发送的,且每一个 channel 有唯一的 ID。

一个 channel 只能被单独一个操作系统线程使用,故投递到特定 channel 上的 message 是有顺序的。但一个操作系统线程上允许使用多个 channel 。channel 号为 0 的 channel 用于处理所有对于当前 connection 全局有效的帧,而 1-65535 号 channel 用于处理和特定 channel 相关的帧。AMQP 协议给出的 channel ,其中每一个 channel 运行在一个独立的线程上,多线程共享同一个 socket。

1、 解耦,系统A在代码中直接调用系统B和系统C的代码,如果将来D系统接入,系统A还需要修改代码,过于麻烦!

2、 异步,将消息写入消息队列,非必要的业务逻辑以异步的方式运行,加快响应速度

3、 削峰,并发量大的时候,所有的请求直接怼到数据库,造成数据库连接异常

系统可用性降低

系统引入的外部依赖越多,越容易挂掉,本来你就是A系统调用BCD三个系统的接口就好了,人ABCD四个系统好好的,没啥问题,你偏加个MQ进来,万一MQ挂了咋整?MQ挂了,整套系统崩溃了,你不就完了么。

系统复杂性提高

硬生生加个MQ进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已

一致性问题

1、 A系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是BCD三个系统那里,BD两个系统写库成功了,结果C系统写库失败了,咋整?你这数据就不一致了。

2、 所以消息队列实际是一种非常复杂的架构,你引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉,最好之后,你会发现,妈呀,系统复杂度提升了一个数量级,也许是复杂了10倍。但是关键时刻,用,还是得用的

DLX,全称为 Dead-Letter-Exchange,死信交换器,死信邮箱。当消息在一个队列中变成死信 (dead message) 之后,它能被重新被发送到另一个交换器中,这个交换器就是 DLX,绑定 DLX 的队列就称之为死信队列。

通过绑定将交换器和队列关联起来,一般会指定一个BindingKey,这样RabbitMq就知道如何正确路由消息到队列了。

At most once:最多一次。消息可能会丢失,单不会重复传输。

At least once:最少一次。消息觉不会丢失,但可能会重复传输。

Exactly once: 恰好一次,每条消息肯定仅传输一次。

vhost 可以理解为虚拟 broker ,即 mini-RabbitMQ server。其内部均含有独立的queue、exchange 和 binding 等,但最最重要的是,其拥有独立的权限系统,可以做到vhost 范围的用户控制。

当然,从 RabbitMQ 的全局角度,vhost 可以作为不同权限隔离的手段(一个典型的例子就是不同的应用可以跑在不同的 vhost 中)。

1、 Module Layer:协议最高层,主要定义了一些客户端调用的命令,客户端可以用这些命令实现自己的业务逻辑。

2、 Session Layer:中间层,主要负责客户端命令发送给服务器,再将服务端应答返回客户端,提供可靠性同步机制和错误处理。

3、 TransportLayer:最底层,主要传输二进制数据流,提供帧的处理、信道服用、错误检测和数据表示等。

1、 星号井号代表通配符

2、 星号代表多个单词,井号代表一个单词

3、 路由功能添加模糊匹配

4、 消息产生者产生消息,把消息交给交换机

5、 交换机根据key的规则模糊匹配到对应的队列,由队列的监听消费者接收消息消费

在我的理解看来就是routing查询的一种模糊匹配,就类似sql的模糊查询方式

1、 Broker: 简单来说就是消息队列服务器实体

2、 Exchange: 消息交换机,它指定消息按什么规则,路由到哪个队列

3、 Queue: 消息队列载体,每个消息都会被投入到一个或多个队列

4、 Binding: 绑定,它的作用就是把exchange和queue按照路由规则绑定起来

5、 Routing Key: 路由关键字,exchange根据这个关键字进行消息投递

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

7、 Producer: 消息生产者,就是投递消息的程序

8、 Consumer: 消息消费者,就是接受消息的程序

9、 Channel: 消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务

由Exchange、Queue、RoutingKey三个才能决定一个从Exchange到Queue的唯一的线路。

生产者

Map<String, Object> argss = new HashMap<String, Object>();argss.put("x-max-priority",10);

消费者

AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()    .priority(5) // 优先级,默认为5,配合队列的 x-max-priority 属性使用

当你在单 node 上声明 queue 时,只要该 node 上相关元数据进行了变更,你就会得到 Queue.Declare-ok 回应;而在 cluster 上声明 queue ,则要求 cluster 上的全部node 都要进行元数据成功更新,才会得到 Queue.Declare-ok 回应。

另外,若 node 类型为 RAM node 则变更的数据仅保存在内存中,若类型为 disk node 则还要变更保存在磁盘上的数据。

消息路由必须有三部分:交换器、路由、绑定。

生产者把消息发布到交换器上,绑定决定了消息如何从路由器路由到特定的队列;消息最终到达队列,并被消费者接收。

  1. 消息发布到交换器时,消息将拥有一个 路由键(routing key) , 在消息创建时设定。
  2. 通过队列路由键,可以把队列绑定到交换器上。
  3. 消息到达交换器后,RabbitMQ会将消息的路由键与队列的路由键进行匹配(针对不同的交换器有不同的路由规则)。如果能够匹配到队列,则消息会投递到相应队列中;如果不能匹配到任何队列,消息将进入"黑洞"。

常用的交换器主要分为以下三种:

  1. direct :如果路由键完全匹配,消息就会被投递到相应的队列;每个AMQP的实现都必须有一个direct交换器,包含一个空白字符串名称的默认交换器。声明一个队列时,会自动绑定到默认交换器,并且以队列名称作为路由键:channel -> basic_public($msg, '', 'queue-name')
  2. fanout : 如果交换器收到消息,将会广播到所有绑定的队列上;
  3. topic :可以使来自不同源头的消息能够到达同一个队列。使用topic交换器时,可以使用通配符,比如:"*" 匹配特定位置的任意文本,"." 把路由键分为了几个标识符, "#" 匹配所有规则等。
  4. 特别注意:发往topic交换器的消息不能随意的设置选择键(routing_key),必须是有"."隔开的一系列的标识符组成。

主要有以下4种。

fanout:把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。

direct:把消息路由到BindingKey和RoutingKey完全匹配的队列中。

topic:

匹配规则:

RoutingKey 为一个 点号'.': 分隔的字符串。 比如: java.xiaoka.show

BindingKey和RoutingKey一样也是点号“.“分隔的字符串。

BindingKey可使用 _ 和 # 用于做模糊匹配,_匹配一个单词,#匹配多个或者0个

headers:不依赖路由键匹配规则路由消息。是根据发送消息内容中的headers属性进行匹配。性能差,基本用不到。

mandatory :true 返回消息给生产者。

mandatory: false 直接丢弃。

通常由以下两部分组成:

rabbit_amqqueue_process:负责协议相关的消息处理,即接收生产者的消息、向消费者交付消息、处理消息的确认(包括生产端的 confirm 和消费端的 ack) 等。

backing_queue:是消息存储的具体形式和引擎,并向 rabbit amqqueue process 提供相关的接口以供调用。

内存节点:ram,将变更写入内存。

磁盘节点:disc,磁盘写入操作。

RabbitMQ要求最少有一个磁盘节点。

内存节点:保存状态到内存,但持久化的队列和消息还是会保存到磁盘;

磁盘节点:保存状态到内存和磁盘,一个集群中至少需要一个磁盘节点

用于保证当镜像 queue 中 master 挂掉时,连接到 slave 上的 consumer 可以收到自身 consume 被取消的通知,进而可以重新执行 consume 动作从新选出的 master 出获得消息。若不采用该机制,连接到 slave 上的 consumer 将不会感知 master 挂掉这个事情,导致后续无法再收到新 master 广播出来的 message 。另外,因为在镜像 queue 模式下,存在将 message 进行 requeue 的可能,所以实现 consumer 的逻辑时需要能够正确处理出现重复 message 的情况。

1、 At most once:最多一次。消息可能会丢失,单不会重复传输。

2、 At least once:最少一次。消息觉不会丢失,但可能会重复传输。

3、 Exactly once:恰好一次,每条消息肯定仅传输一次。

RabbitMQ 客户端中与事务机制相关的方法有三个:

channel.txSelect 用于将当前的信道设置成事务模式。

channel 、txCommit 用于提交事务 。

channel 、txRollback 用于事务回滚,如果在事务提交执行之前由于 RabbitMQ 异常崩溃或者其他原因抛出异常,通过txRollback来回滚。

在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重和幂等的依据(消息投递失败并重传),避免重复的消息进入队列;在消息消费时,要求消息体中必须要有一个bizId(对于同一业务全局唯一,如支付ID、订单ID、帖子ID等)作为去重和幂等的依据,避免同一条消息被重复消费。

这个问题针对业务场景来答分以下几点:

1、 拿到这个消息做数据库的insert操作。然后给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。

2、 拿到这个消息做Redis的set的操作,因为你无论set几次结果都是一样的,set操作本来就算幂等操作。

3、 如果上面两种情况还不行。准备一个第三方介质,来做消费记录。以Redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入Redis。那消费者开始消费前,先去Redis中查询有没消费记录即可。

255 字节。

消费者收到的每一条消息都必须进行确认(自动确认和自行确认)

消费者在声明队列时,可以置顶autoAck参数,当autoAck = false时,RabbitMQ会等待消费者显式发送回 ack 信号后才从内存(和磁盘,如果是持久化消息的话)中删除消息,否则RabbitMQ会在队列中消息被消费后立即删除它。

采用消息确认机制后,只要使 autoAck = false,消费者就有足够的时间处理消息(任务),不用担心处理消息过程中消费者进程挂掉后消息丢失的问题,因为RabbitMQ会一直持有消息直到消费者显式调用basicAck为止。

当autoAck = false时,对于RabbitMQ服务器端而言,队列中的消息分成了两部分:一部分是等待投递给消费者的消息;一部分是已经投递给消费者,但是还没有收到消费者ack信号的消息。如果服务器端一直没有收到消费者的ack信号,并且消费此消息的消费者已经断开连接,则服务器端会安排该消息 重新进入队列,等待投递给下一个消费者(也可能还是原来的那个消费者)。

RabbitMQ不会为 ack消息设置超时时间,它判断此消息是否需要重新投递给消费者的唯一依据是消费该消息的消费者连接是否已经断开。这么设计的原因是RabbitMQ允许消费者消费一条消息的时间可以很久很久。

利用TTL(队列的消息存活时间或者消息存活时间),加上死信交换机

// 设置属性,消息10秒钟过期AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().expiration("10000") // TTL// 指定队列的死信交换机Map<String,Object> arguments = new HashMap<String,Object>();arguments.put("x-dead-letter-exchange","DLX_EXCHANGE");

从概念上来说,消息路由必须有三部分:交换器、路由、绑定。生产者把消息到交换器上;绑定决定了消息如何从路由器路由到特定的队列;消息最终到达队列,并被消费者接收。

消息到交换器时,消息将拥有一个路由键(routing key),在消息创建时设定。通过队列路由键,可以把队列绑定到交换器上。消息到达交换器后,RabbitMQ会将消息的路由键与队列的路由键进行匹配(针对不同的交换器有不同的路由规则)。如果能够匹配到队列,则消息会投递到相应队列中;如果不能匹配到任何队列,消息将进入 “黑洞”。

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

1、 direct:如果路由键完全匹配,消息就被投递到相应的队列

2、 fanout:如果交换器收到消息,将会广播到所有绑定的队列上

3、 topic:可以使来自不同源头的消息能够到达同一个队列。使用topic交换器时,可以使用通配符。比如:“*” 匹配特定位置的任意文本, “.” 把路由键分为了几部分,“#” 匹配所有规则等。特别注意:发往topic交换器的消息不能随意的设置选择键(routing_key),必须是由"."隔开的一系列的标识符组成。

更对 RabbitMQ 面试题 50道

01、 
02、 
03、 
04、 
05、 
06、 
07、 
08、 
09、 
10、 

11、 
12、 
13、 
14、 
15、 
16、 
17、 
18、 
19、 
20、 

21、 
22、 
23、 
24、 
25、 
26、 
27、 
28、 
29、 
30、 

31、 
32、 
33、 
34、 
35、 
36、 
37、 
38、 
39、 
40、 

41、 
42、 
43、 
44、 
45、 
46、 
47、 
48、 
49、 
50、 

 如果不背 RabbitMQ 面试题的答案,肯定面试会挂!

这套RabbitMQ面试题大全,希望对大家有帮助哈~

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发