RabbitMQ 面试那点事儿(二)

本博文接上篇《RabbitMQ面试那点事儿》,再梳理下RabbitMQ关于面试的一些知识点,本博文包含了RabbitMQ集群和高可用方面的知识

1. 如何保证RabbitMQ的消息的顺序性

对于这个问题,我查阅很多网上的资料,大体来说主流的解决方案有两种:

  • 一种是使用单线程消费来保证消息的顺序性
  • 对消息进行编号,消费者处理时根据编号来判断顺序

乍一看,觉得两种方案没有什么问题,但是深入了解下,觉得这两种解决方案并不能完全接保证消息的消费的顺序性问题。

首先我们来分析下,是什么导致RabbitMQ消息的顺序性问题的,常见的有以下几种情形:

  • 消息生产者启用了发送确认机制,在发生超时、中断等,需要RabbitMQ补偿发送时,那么此时消息在源头就已经出现顺序混乱了,导致消息被消费时也是乱序的
  • 另一种情况,如果消息发送时,设置了超时时间,并且采用了死信队列,模拟了延时队列的效果,那么此时消息的顺序也时不能保证的
  • 还有一种情况,如果消息设置了优先级,那么在高并发的情况下,消息的顺序也是得不到保证的,消息的消费顺序也就不能保证了

刚才我们分析了出现消息乱序的几种情况,这里我们首先排除了实用单线程来消费,原因很简单,发送的消息的顺序(源头数据的顺序出现了异常)出现了异常,单线程消费的顺序肯定也是异常的

其次对消息进行编号,这个可以解决消息顺序的问题,但是对加大了对业务处理的复杂性。

2. 如果RabbitMQ阻塞大量消息待消费,该怎么处理

一般情况下,出现这种情况,肯定是先紧急处理现场的情况, 将RabbitMQ服务中堆积的阻塞的消息消费掉, 怎么消费呢,目前能尽快处理的方案可以如下操作:

  • 一般只有比较重要的业务消息才会存储在磁盘中就行持久化(这样做主要是为了提高rabbitMQ的性能,消息全部持久化的话,对RabbitMQ的性能损耗是很高的)
  • 可以通过新增多个消费者来监听业务队列来提高消息的消费速度
  • 或者通过设置并发提高消息的消费速度

以上只是一个应急的解决方案,我们还需要从源头来处理分析和减少消息阻塞的现象
消息阻塞常见的有两种情况:

  • 消息生产的速度大于消息消费的速度
  • 架构设计有问题,对于消费失败的消息没有采取措施,导致消费失败的消息不断被RabbitMQ重新发送给消费者,导致消息阻塞

针对上面两种情况,我们分别进行处理

  • 消息生产的速度大于消息消费的速度,我们可以设置channel.basicQos(n)来限制RabbitMQ队列中最大的未确认的消息数量,超过这个数量,rabbitMQ就不在接收生产者生产的消息,这个也是RabbitMQ的优点:削峰填谷
  • 针对第二个,只能修改架构设计了,我们一方面可以通过给队列设置死信队列,同时消费端进行业务控制,如果同一个消息被消费端同时消费一次数量以上(这个数量可以通过配置参数来自由控制)将该消息手动拒绝,这样消息就会进入死信队列,然后由死信队列进行消息的持久化,或者其他的处理

3. 如何保证RabbitMQ的负载均衡和高可用

保证RabbitMQ的负载均衡和高可用,我们可以使用RabbitMQ的普通集群、镜像集群来实现

  • 普通集群

多个RabbitMQ服务安装在多个服务器上,通过RabbitMQ提供的命令来构建RabbitMQ的集群,RabbitMQ的集群比较简单,是依赖erlang集群,而erlang集群是通过这个cookie进行通信认证的,因此我们做集群的第一步就是干cookie,这个也是最重要的,其次使用RabbitMQ内部的命令来实现元数据之间的交互

那么RabbitMQ是怎么来实现消费者在任意一个节点上消费,即使队列节点不在这个RabbitMQ服务上也能消费呢?

RabbitMQ构建集群之后,就会在各个节点之间共享元数据,元数据里面保存在该队列在哪个RabbitMQ服务的节点上,只要有消费者请求消费该节点上的消息时,该节点就是向真正有该队列的实际数据的RabbitMQ服务节点拉取消息来推送给消费者,这样就实现了消费者监听任一节点上的队列,都是能消费该队列上的消息

普通集群主要是加大了RabbitMQ提供服务的吞吐量,能在任意一个节点出现故障,不能对外提供服务时,只需要让消费者监听其他正常的节点即可(利用HAProxy可以解决)

普通集群的模式的优点不多,但是缺点不少:

  1. 可能会造成RabbitMQ服务内部产生大量的数据传输
  2. 可用性几乎没有,如果节点中的任意节点出现了故障,不能对外服务了,其上的队列交换机等全部不可用
  • 镜像集群模式

可以这么说,该模式才是RabbitMQ真正的高可用模式,镜像,顾名思义就是每个节点上都有Queue的所有的数据,这样就能完美解决普通集群模式中的第二个缺点了,每个节点都能queue的完整的数据,任意一个节点出现了故障,其他的节点上还包含该queue的全部的数据,消费者也是可以消费到数据的

镜像模式依据的是策略,镜像模式在是普通模式的基础上进行的,可以在界面控制台上或者命令来实现镜像模式的搭建,比如说创建queue时,指定该queue创建或者收到消息时需要同步一个或者多个集群节点上

4. 什么是元数据?元数据分为哪些类型?包括哪些内容?与cluster相关的元数据有哪些?元数据是如何保存的?元数据在cluster中是如何分布的

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

5. blackholed问题?如何避免blackholed问题?

什么是blackholed问题呢?可以思考下以下的问题:

  • 如果exchange没有绑定queue,此时向exchange发送消息。
  • exchange通过bindingKeyA与queueA绑定,但是发送消息时,指定了bindingKeyB来发送消息。

以上两种情况就会出现blackholed问题,造成的结果就是消息的丢失

那么该如何解决这个问题呢?
这个问题的解决方案其实在《RabbitMQ面试那点事儿》已经提到过,我们启用发送者确认机制,也可以开启mandatory来实现消息的备份等问题。

你可能感兴趣的:(RabbitMQ 面试那点事儿(二))