带你一起了解RabbitMQ集群原理 - 极悦
首页 课程 师资 教程 报名

带你一起了解RabbitMQ集群原理

  • 2022-07-22 09:44:59
  • 1708次 极悦

Java教程中,大家会学习RabbitMQ,那么,RabbitMQ集群原理是什么?极悦小编来带大家一起了解一下。

1.RabbitMQ默认集群原理

RabbitMQ 本身是基于 Erlang 编写的,Erlang 语言本质上是分布式的(通过同步 Erlang 集群各个节点的 erlang.cookie 来实现)。因此,RabbitMQ 自然支持集群。集群是保证可靠性的一种方式,同时可以横向扩展,达到提高消息吞吐量的目的。

下图显示了一个集群示例:

上面图中采用三个节点组成了一个RabbitMQ的集群,Exchange A(交换器)的元数据信息在所有节点上是一致的,而Queue(存放消息的队列)的完整数据则只会存在于它所创建的那个节点上。,其他节点只知道这个queue的metadata信息和一个指向queue的owner node的指针。

RabbitMQ集群元数据的同步

RabbitMQ集群会始终同步四种类型的内部元数据:

a. 队列元数据:队列名称和它的属性

b. 交换器元数据:交换器名称、类型和属性

c. 绑定元数据:一张简单的表格展示了如何将消息路由到队列

d. vhost元数据:为vhost内的队列、交换器和绑定提供命名空间和安全属性

因此,当用户访问其中任何一个RabbitMQ节点时,通过rabbitmqctl查询到的queue/user/exchange/vhost等信息都是相同的。

为什么 RabbitMQ 集群只使用元数据同步?

(1)存储空间。如果每个集群节点都有所有Queue的完整数据副本,那么每个节点的存储空间会非常大,集群的消息积压能力会很弱(消息积压能力无法通过扩容来提升)集群节点);

(2)性能。消息的发布者需要将消息复制到每个集群节点。对于持久化消息,网络和磁盘同步复制的开销会显着增加。

2.RabbitMQ集群发送/订阅消息的基本原理

RabbitMQ集群工作原理图如下:

客户端直接连接队列所在节点

如果消息生产者或消息消费者通过amqp-client的客户端连接到节点1发布或订阅消息,那么此时集群中的消息发送和接收只与节点1相关。

客户端连接到非队列数据所在节点

如果消息生产者连接到节点2或节点3,队列1的完整数据不在这两个节点上,那么这两个节点在发送消息的过程中主要起到路由转发的作用,根据这两个节点上的元数据被转发到节点1,最终发送的消息仍然会存储在节点1的队列1中。同样,如果消息消费者连接的节点2或节点3,这两个节点也会充当路由节点转发消息,消息会从节点1的队列1中拉取消费。

集群节点类型

磁盘节点:在磁盘上存储配置信息和元信息(单节点系统必须是磁盘节点,否则每次重启RabbitMQ都会丢失所有系统配置信息)。

内存节点:在内存中存储配置信息和元信息。性能优于磁盘节点。

RabbitMQ 要求集群中至少有一个磁盘节点。当节点加入和离开集群时,必须通知磁盘节点(如果集群中唯一的磁盘节点崩溃,则不能创建队列、创建交换机、创建绑定、添加用户、更改权限、添加和删除集群节点)。简而言之,如果唯一磁盘的磁盘节点崩溃,集群可以继续运行,但什么都不能改变。因此,建议在集群中设置两个磁盘节点,只要一个可用,就可以正常运行。

概括

普通集群模式不保证队列的高可用。虽然交换机和绑定可以复制到集群中的任何节点,但不会复制队列的内容。这种模式虽然解决了一个项目组的节点压力,但是队列节点的宕机直接导致队列不可用,只能等待重启。因此,如果要在队列节点宕机或故障时正常工作,必须将队列的内容复制到集群中的各个节点,并且必须创建镜像队列。

3.RabbitMQ镜像队列原理

镜像队列是在普通集群模式的基础上,再加入一些策略。所以必须先配置普通集群,然后才能设置镜像队列。镜像队列存在于多个节点上。要实现镜像模式,需要先搭建一个普通的集群模式,然后在这个模式的基础上配置镜像模式,实现高可用。

镜像队列的结构

镜像队列基本上就是一个特殊的BackingQueue,它包装了一个普通的BackingQueue,用于本地消息持久化处理,并在此基础上增加了复制消息和确认所有镜像的功能。mirror_queue_master 上的所有操作都会通过可靠的多播 GM 同步到各个从节点。GM负责消息的广播,mirror_queue_slave负责回调处理,master上的回调处理由coordinator完成。mirror_queue_slave包含了普通的BackingQueue用于消息存储,主节点的BackingQueue包含在mirror_queue_master中,被AMQQueue调用。

消息的发布(Basic.Publish除外)和消费都是通过主节点完成的。主节点在处理消息的同时,通过 GM 将消息的处理动作广播给所有从节点。slave节点的GM收到消息后,通过回调将消息交还给mirror_queue_slave进行实际处理。

对于 Basic.Publish,消息同时发送到主服务器和所有从服务器。如果此时master宕机了,消息也会发给slave,这样slave提升为master时消息就不会丢失。

GM(保证组播)

GM模块实现的一种可靠的组播通信协议,可以保证组播消息的原子性,即保证组内所有存活的节点都收到或不收到消息。

其实现大致如下:

所有节点组成一个循环链表,每个节点都会监控自己左右两边的节点。当添加一个节点时,相邻节点保证将当前广播消息复制到新节点;当某个节点发生故障时,相邻节点将接管,以确保将广播消息复制到所有节点。主节点和从节点上的这些gm组成一个组,组的信息(gm_group)会记录在mnesia中。不同的镜像队列形成不同的组。消息从主节点发送到gm后,沿着链表依次传递给所有节点。由于所有节点形成一个循环链表,主节点对应的gm最终会收到自己发送的消息。此时,主节点将知道消息已发送。复制到所有从节点。

新节点

新节点的加入流程如下图所示:

每当节点加入或重新加入(例如从网络分区恢复)镜像队列时,之前保存的队列内容将被清除。

在现有镜像队列中添加新节点时,默认ha-sync-mode=manual,除非显式调用同步命令,否则镜像队列中的消息不会主动同步到新节点。当调用同步命令时,队列开始阻塞,直到同步完成才能操作。

当 ha-sync-mode=automatic 时,添加新节点时默认同步已知镜像队列。由于同步过程的限制,不建议在生产消费队列中操作。

节点故障

如果一个从站发生故障,系统除了记录之外几乎什么都不做。master还是master,client不需要做任何动作,也不需要通知slave的失败。如果主站失败,则必须选择其中一个从站作为主站。被选为新master的slave通常是最老的,因为最老的slave和之前的master之间的同步状态应该是最好的。但是需要注意的是,如果没有slave与master完全同步,那么之前master中未同步的消息就会丢失。

概括

镜像节点在集群中的其他节点上拥有从属队列的副本。一旦主节点不可用,最旧的从队列将被选为新的主队列。但是镜像队列不能用作负载均衡器,因为每个操作都必须在所有节点上完成。这种模式的副作用也很明显。除了降低系统性能外,如果镜像队列过多,大量消息进入,集群内部的网络带宽也会被这种同步通信大大消耗。因此,适用于对可靠性要求较高的场合。

以上就是关于“带你一起了解RabbitMQ集群原理”的介绍,大家如果对此比较感兴趣,想了解更多相关知识,可以关注一下极悦的RabbitMQ教程,里面有更丰富的知识等着大家去学习,希望对大家能够有所帮助。

选你想看

你适合学Java吗?4大专业测评方法

代码逻辑 吸收能力 技术学习能力 综合素质

先测评确定适合在学习

在线申请免费测试名额
价值1998元实验班免费学
姓名
手机
提交