1:集群结构
1.1:概述
通过 Erlang 的分布式特性(通过 magic cookie 认证节点)进行 RabbitMQ 集群,各 RabbitMQ 服务为对等节点,即每个节点都提供服务给客户端连接,进行消息发送与接收。
这些节点通过 RabbitMQ HA 队列(镜像队列)进行消息队列结构复制。本方案中搭建 3 个节点,并且都是磁盘节点(所有节点状态保持一致,节点完全对等),只要有任何一个节点能够工作,RabbitMQ 集群对外就能提供服务。
1.2:元数据
RabbitMQ 内部有各种基础构件,包括队列、交换器、绑定、虚拟主机等,他们组成了 AMQP 协议消息通信的基础,而这些构件以元数据的形式存在,它始终记录在 RabbitMQ 内部,它们分别是:
1:队列元数据:队列名称和它们的属性
2:交换器元数据:交换器名称、类型和属性
3:绑定元数据:一张简单的表格展示了如何将消息路由到队列
4:vhost 元数据:为 vhost 内的队列、交换器和绑定提供命名空间和安全属性
在单一节点上,RabbitMQ 会将上述元数据存储到内存上,如果是磁盘节点(下面会讲),还会存储到磁盘上。
1.3:集群中的队列
这里有个问题需要思考,RabbitMQ 默认会将消息冗余到所有节点上吗?这样听起来正符合高可用的特性,只要集群上还有一个节点存活,那么就可以继续进行消息通信,但这也随之为 RabbitMQ 带来了致命的缺点:
1:每次发布消息,都要把它扩散到所有节点上,而且对于磁盘节点来说,每一条消息都会触发磁盘活动,这会导致整个集群内性能负载急剧拉升。
2:如果每个节点都有所有队列的完整内容,那么添加节点不会给你带来额外的存储空间,也会带来木桶效应,举个例子,如果集群内有个节点存储了 3G 队列内容,那么在另外一个只有 1G 存储空间的节点上,就会造成内存空间不足的情况,也就是无法通过集群节点的扩容提高消息积压能力。
解决这个问题就是通过集群中唯一节点来负责任何特定队列,只有该节点才会受队列大小的影响,其它节点如果接收到该队列消息,那么就要根据元数据信息,传递给队列所有者节点(也就是说其它节点上只存储了特定队列所有者节点的指针)。这样一来,就可以通过在集群内增加节点,存储更多的队列数据。
1.4:分布交换器
交换器其实是我们想象出来的,它本质是一张查询表,里面包括了交换器名称和一个队列的绑定列表,当你将消息发布到交换器中,实际上是你所在的信道将消息上的路由键与交换器的绑定列表进行匹配,然后将消息路由出去。有了这个机制,那么在所有节点上传递交换器消息将简单很多,而 RabbitMQ 所做的事情就是把交换器拷贝到所有节点上,因此每个节点上的每条信道都可以访问完整的交换器了。

1.5:内存节点与磁盘节点
关于上面队列所说的问题与解决办法,又有了一个伴随而来的问题出现:如果特定队列的所有者节点发生了故障,那么该节点上的队列和关联的绑定都会消失吗?
1:如果是内存节点,那么附加在该节点上的队列和其关联的绑定都会丢失,并且消费者可以重新连接集群并重新创建队列;
2:如果是磁盘节点,重新恢复故障后,该队列又可以进行传输数据了,并且在恢复故障磁盘节点之前,不能在其它节点上让消费者重新连到集群并重新创建队列,如果消费者继续在其它节点上声明该队列,会得到一个 404 NOT_FOUND 错误,这样确保了当故障节点恢复后加入集群,该节点上的队列消息不回丢失,也避免了队列会在一个节点以上出现冗余的问题。
接下来说说内存节点与磁盘节点在集群中的作用,在集群中的每个节点,要么是内存节点,要么是磁盘节点,如果是内存节点,会将所有的元数据信息仅存储到内存中,而磁盘节点则不仅会将所有元数据存储到内存上, 还会将其持久化到磁盘。
在单节点 RabbitMQ 上,仅允许该节点是磁盘节点,这样确保了节点发生故障或重启节点之后,所有关于系统的配置与元数据信息都会重磁盘上恢复;而在 RabbitMQ 集群上,允许节点上至少有一个磁盘节点,在内存节点上,意味着队列和交换器声明之类的操作会更加快速。原因是这些操作会将其元数据同步到所有节点上,对于内存节点,将需要同步的元数据写进内存就行了,但对于磁盘节点,意味着还需要及其消耗性能的磁盘写入操作。
RabbitMQ 集群只要求至少有一个磁盘节点,这是有道理的,当其它内存节点发生故障或离开集群,只需要通知至少一个磁盘节点进行元数据的更新,如果是碰巧唯一的磁盘节点也发生故障了,集群可以继续路由消息,但是不可以做以下操作了:
1:创建队列
2:创建交换器
3:创建绑定
4:添加用户
5:更改权限
6:添加或删除集群节点
这是因为上述操作都需要持久化到磁盘节点上,以便内存节点恢复故障可以从磁盘节点上恢复元数据,解决办法是在集群添加 2 台以上的磁盘节点,这样其中一台发生故障了,集群仍然可以保持运行,且能够在任何时候保存元数据变更。
2:部署
2.1:环境准备
| rabbitmq-1 |
2C2G |
10.0.0.10 |
| rabbitmq-2 |
2C2G |
10.0.0.11 |
| rabbitmq-3 |
2C2G |
10.0.0.12 |
2.2:基础环境安装(三台机器同时操作)
# 安装 Erlang
[root@rabbitmq-1 ~]# ls
anaconda-ks.cfg esl-erlang_24.3.3-1_centos_7_amd64.rpm
[root@rabbitmq-2 ~]# ls
anaconda-ks.cfg esl-erlang_24.3.3-1_centos_7_amd64.rpm
[root@rabbitmq-3 ~]# ls
anaconda-ks.cfg esl-erlang_24.3.3-1_centos_7_amd64.rpm
[root@rabbitmq-1 ~]# yum localinstall -y esl-erlang_24.3.3-1_centos_7_amd64.rpm
[root@rabbitmq-2 ~]# yum localinstall -y esl-erlang_24.3.3-1_centos_7_amd64.rpm
[root@rabbitmq-3 ~]# yum localinstall -y esl-erlang_24.3.3-1_centos_7_amd64.rpm
# 测试erlang
[root@rabbitmq-1 ~]# erl
Erlang/OTP 24 [erts-12.3.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1]
Eshell V12.3.1 (abort with ^G)
1> 1+1.
2
2.3:安装RabbitMQ(三台机器同时操作)
[root@rabbitmq-1 ~]# wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.9.16/rabbitmq-server-3.9.16-1.el7.noarch.rpm
[root@rabbitmq-1 ~]# yum localinstall -y rabbitmq-server-3.9.16-1.el7.noarch.rpm
2.4:配置并启动服务(三台机器同时操作)
[root@rabbitmq-1 ~]# cat << eof>> /etc/rabbitmq/rabbitmq.config
> [{rabbit, [{loopback_users, []}]}].
> eof
[root@rabbitmq-1 ~]# cat /etc/rabbitmq/rabbitmq.config
[{rabbit, [{loopback_users, []}]}].
# 这里的意思是开放使用,rabbitmq 默认创建的用户 guest,密码也是 guest,这个用户默认只能是本机访问,localhost 或者 127.0.0.1,从外部访问需要添加上面的配置。
# 保存配置之后启动服务
[root@rabbitmq-1 ~]# systemctl enable rabbitmq-server.service --now
Created symlink from /etc/systemd/system/multi-user.target.wants/rabbitmq-server.service to /usr/lib/systemd/system/rabbitmq-server.service. # 启动并注册到开机自启
2.5:启动Web管理(三台机器同时操作)
[root@rabbitmq-1 ~]# /sbin/rabbitmq-plugins enable rabbitmq_management
Enabling plugins on node rabbit@rabbitmq-1:
rabbitmq_management
The following plugins have been configured:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_web_dispatch
Applying plugin configuration to rabbit@rabbitmq-1...
The following plugins have been enabled:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_web_dispatch
started 3 plugins.
2.6:测试访问
访问:http://10.0.0.10:15672 http://10.0.0.11:15672 http://10.0.0.12:15672
用户名:guest
密码:guest

3:集群配置
3.1:配置解析并停止RabbitMQ服务(三台机器同时操作)
# 因为我hostname已经修改了,这里写入一下host解析三台机器即可,大家需要改下host哈
[root@rabbitmq-1 ~]# cat << eof>> /etc/hosts
> 10.0.0.10 rabbitmq-1
> 10.0.0.11 rabbitmq-2
> 10.0.0.12 rabbitmq-3
> eof
[root@rabbitmq-1 ~]#
[root@rabbitmq-1 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.10 rabbitmq-1
10.0.0.11 rabbitmq-2
10.0.0.12 rabbitmq-3
# 注意:三台主机上安装的 RabbitMQ 都保证都可以正常启动, 才可以进行以下操作
# 停止服务
[root@rabbitmq-1 ~]# systemctl stop rabbitmq-server.service
3.2:设置 Erlang Cookie
设置不同节点间同一认证的 Erlang Cookie,这里将 rabbitmq-1 的 Cookie 传给另外两台。
[root@rabbitmq-1 ~]# scp /var/lib/rabbitmq/.erlang.cookie root@rabbitmq-2:/var/lib/rabbitmq/
[root@rabbitmq-1 ~]# scp /var/lib/rabbitmq/.erlang.cookie root@rabbitmq-3:/var/lib/rabbitmq/
# 注:
cookie 在所有节点上必须完全一样,同步时一定要注意。 erlang 是通过主机名来连接服务,必须保证各个主机名之间可以 ping 通。可以通过编辑 /etc/hosts 来手工添加主机名和 IP 对应关系。如果主机名 ping 不通,rabbitmq 服务启动会失败
3.3:启动节点(三台机器同时操作)
# 重启节点(三台机器同时操作)
[root@rabbitmq-1 ~]# rabbitmq-server -detached
# 查看单节点的集群状态。
[root@rabbitmq-1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-1 ...
---
[root@rabbitmq-2 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-2 ...
---
[root@rabbitmq-3 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-3 ...
---
3.4:加入集群
这里将 rabbitmq-2 和 rabbitmq-3 加入到 rabbitmq-1 中,按照顺序执行 先rabbitmq-2,rabbitmq-3
[root@rabbitmq-2 ~]# rabbitmqctl stop_app # 停止rabbitmq服务
Stopping rabbit application on node rabbit@rabbitmq-2 ...
[root@rabbitmq-2 ~]# rabbitmqctl join_cluster rabbit@rabbitmq-1 # rabbitmq-2和rabbitmq-1构成集群, rabbitmq-2必须能通过rabbitmq-1的主机名ping通
Clustering node rabbit@rabbitmq-2 with rabbit@rabbitmq-1
[root@rabbitmq-2 ~]# rabbitmqctl start_app # 开启rabbitmq服务
Starting node rabbit@rabbitmq-2 ...
[root@rabbitmq-3 ~]# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@rabbitmq-3 ...
[root@rabbitmq-3 ~]# rabbitmqctl join_cluster rabbit@rabbitmq-1
Clustering node rabbit@rabbitmq-3 with rabbit@rabbitmq-1
[root@rabbitmq-3 ~]# rabbitmqctl start_app
Starting node rabbit@rabbitmq-3 ...
3.5:查看集群
# 检查集群
[root@rabbitmq-1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-1 ...
Basics
Cluster name: rabbit@rabbitmq-1
Disk Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
rabbit@rabbitmq-3
Running Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
rabbit@rabbitmq-3
Versions
rabbit@rabbitmq-1: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-2: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-3: RabbitMQ 3.9.16 on Erlang 24.3.3
Maintenance status
Node: rabbit@rabbitmq-1, status: not under maintenance
Node: rabbit@rabbitmq-2, status: not under maintenance
Node: rabbit@rabbitmq-3, status: not under maintenance
Alarms
(none)
Network Partitions
(none)
Listeners
Node: rabbit@rabbitmq-1, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-1, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-1, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-2, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-2, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-2, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-3, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-3, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-3, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Feature flags
Flag: drop_unroutable_metric, state: disabled
Flag: empty_basic_get_metric, state: disabled
Flag: implicit_default_bindings, state: enabled
Flag: maintenance_mode_status, state: enabled
Flag: quorum_queue, state: enabled
Flag: stream_queue, state: enabled
Flag: user_limits, state: enabled
Flag: virtual_host_metadata, state: enabled
# 如果要为集群增加新节点时,我们可以按照上面的步骤将新节点添加到集群。
4:故障测试
4.1:停止一个节点
在集群中如果要停止一个节点执行命令 rabbitmqctl stop_app 或 rabbitmqctl stop 或者可以 kill 掉节点的进程不影响其他节点运行(注意: 如果只有一个磁盘节点,如果干掉磁盘节点后消息数据会丢失)。
# 停止 rabbitmq-3
[root@rabbitmq-3 ~]# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@rabbitmq-3 ...
# 查看集群状态
[root@rabbitmq-1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-1 ...
Basics
Cluster name: rabbit@rabbitmq-1
Disk Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
rabbit@rabbitmq-3
Running Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
Versions
rabbit@rabbitmq-1: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-2: RabbitMQ 3.9.16 on Erlang 24.3.3
Maintenance status
Node: rabbit@rabbitmq-1, status: not under maintenance
Node: rabbit@rabbitmq-2, status: not under maintenance
Alarms
(none)
Network Partitions
(none)
Listeners
Node: rabbit@rabbitmq-1, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-1, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-1, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-2, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-2, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-2, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Feature flags
Flag: drop_unroutable_metric, state: disabled
Flag: empty_basic_get_metric, state: disabled
Flag: implicit_default_bindings, state: enabled
Flag: maintenance_mode_status, state: enabled
Flag: quorum_queue, state: enabled
Flag: stream_queue, state: enabled
Flag: user_limits, state: enabled
Flag: virtual_host_metadata, state: enabled
4.2:重置一个节点
刚刚将 rabbitmq-3 给停止了,如果再次启动node3,那么还会加入到节点中来。
[root@rabbitmq-3 ~]# rabbitmqctl start_app
Starting node rabbit@rabbitmq-3 ...
# 查看集群
[root@rabbitmq-1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-1 ...
Basics
Cluster name: rabbit@rabbitmq-1
Disk Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
rabbit@rabbitmq-3
Running Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
rabbit@rabbitmq-3
Versions
rabbit@rabbitmq-1: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-2: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-3: RabbitMQ 3.9.16 on Erlang 24.3.3
Maintenance status
Node: rabbit@rabbitmq-1, status: not under maintenance
Node: rabbit@rabbitmq-2, status: not under maintenance
Node: rabbit@rabbitmq-3, status: not under maintenance
Alarms
(none)
Network Partitions
(none)
Listeners
Node: rabbit@rabbitmq-1, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-1, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-1, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-2, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-2, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-2, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-3, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-3, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-3, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Feature flags
Flag: drop_unroutable_metric, state: disabled
Flag: empty_basic_get_metric, state: disabled
Flag: implicit_default_bindings, state: enabled
Flag: maintenance_mode_status, state: enabled
Flag: quorum_queue, state: enabled
Flag: stream_queue, state: enabled
Flag: user_limits, state: enabled
Flag: virtual_host_metadata, state: enabled
# 那么,如果才能将一个节点重置,与集群彻底脱离呢。
[root@rabbitmq-3 ~]# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@rabbitmq-3 ...
[root@rabbitmq-3 ~]# rabbitmqctl reset
Resetting node rabbit@rabbitmq-3 ...
[root@rabbitmq-3 ~]# rabbitmqctl start_app
Starting node rabbit@rabbitmq-3 ...
# 然后再查看一下分离之后的集群状态
# rabbitmq-1集群
[root@rabbitmq-1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-1 ...
Basics
Cluster name: rabbit@rabbitmq-1
Disk Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
Running Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
Versions
rabbit@rabbitmq-1: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-2: RabbitMQ 3.9.16 on Erlang 24.3.3
Maintenance status
Node: rabbit@rabbitmq-1, status: not under maintenance
Node: rabbit@rabbitmq-2, status: not under maintenance
Alarms
(none)
Network Partitions
(none)
Listeners
Node: rabbit@rabbitmq-1, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-1, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-1, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-2, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-2, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-2, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Feature flags
Flag: drop_unroutable_metric, state: disabled
Flag: empty_basic_get_metric, state: disabled
Flag: implicit_default_bindings, state: enabled
Flag: maintenance_mode_status, state: enabled
Flag: quorum_queue, state: enabled
Flag: stream_queue, state: enabled
Flag: user_limits, state: enabled
Flag: virtual_host_metadata, state: enabled
# rabbitmq-3集群
[root@rabbitmq-3 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-3 ...
Basics
Cluster name: rabbit@rabbitmq-3
Disk Nodes
rabbit@rabbitmq-3
Running Nodes
rabbit@rabbitmq-3
Versions
rabbit@rabbitmq-3: RabbitMQ 3.9.16 on Erlang 24.3.3
Maintenance status
Node: rabbit@rabbitmq-3, status: not under maintenance
Alarms
(none)
Network Partitions
(none)
Listeners
Node: rabbit@rabbitmq-3, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-3, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-3, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Feature flags
Flag: drop_unroutable_metric, state: enabled
Flag: empty_basic_get_metric, state: enabled
Flag: implicit_default_bindings, state: enabled
Flag: maintenance_mode_status, state: enabled
Flag: quorum_queue, state: enabled
Flag: stream_queue, state: enabled
Flag: user_limits, state: enabled
Flag: virtual_host_metadata, state: enabled
4.3:设置内存节点
上边两个节点加入集群的时候,默认的是作为磁盘节点,如果想要创建内存节点,只需在创建的时候多加一个--ram参数即可。
这里重新加入的时候 如果中间启动过,那么就要关闭后再次配置一下cookie哦
# 中间我是保持reset的状态的哈
[root@rabbitmq-1 ~]# scp /var/lib/rabbitmq/.erlang.cookie root@rabbitmq-3:/var/lib/rabbitmq/
[root@rabbitmq-3 ~]# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@rabbitmq-3 ...
[root@rabbitmq-3 ~]# rabbitmqctl join_cluster rabbit@rabbitmq-1 --ram
Clustering node rabbit@rabbitmq-3 with rabbit@rabbitmq-1
[root@rabbitmq-3 ~]# rabbitmqctl start_app
Starting node rabbit@rabbitmq-3 ...
# 查看集群中的RAM服务器
[root@rabbitmq-1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-1 ...
Basics
Cluster name: rabbit@rabbitmq-1
Disk Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
RAM Nodes
rabbit@rabbitmq-3 # 这里就是RAM服务器了
Running Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
rabbit@rabbitmq-3
Versions
rabbit@rabbitmq-1: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-2: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-3: RabbitMQ 3.9.16 on Erlang 24.3.3
Maintenance status
Node: rabbit@rabbitmq-1, status: not under maintenance
Node: rabbit@rabbitmq-2, status: not under maintenance
Node: rabbit@rabbitmq-3, status: not under maintenance
Alarms
(none)
Network Partitions
(none)
Listeners
Node: rabbit@rabbitmq-1, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-1, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-1, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-2, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-2, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-2, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-3, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-3, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-3, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Feature flags
Flag: drop_unroutable_metric, state: enabled
Flag: empty_basic_get_metric, state: enabled
Flag: implicit_default_bindings, state: enabled
Flag: maintenance_mode_status, state: enabled
Flag: quorum_queue, state: enabled
Flag: stream_queue, state: enabled
Flag: user_limits, state: enabled
Flag: virtual_host_metadata, state: enabled
# 在 RabbitMQ 集群里,必须至少有一个磁盘节点存在
4.4:更改节点属性
# 先将刚刚的 rabbitmq-3 改回到磁盘节点:
[root@rabbitmq-3 ~]# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@rabbitmq-3 ...
[root@rabbitmq-3 ~]# rabbitmqctl change_cluster_node_type disc
[root@rabbitmq-3 ~]# rabbitmqctl start_app
Starting node rabbit@rabbitmq-3 ...
# 查看集群属性
[root@rabbitmq-1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-1 ...
Basics
Cluster name: rabbit@rabbitmq-1
Disk Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
rabbit@rabbitmq-3
Running Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
rabbit@rabbitmq-3
Versions
rabbit@rabbitmq-1: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-2: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-3: RabbitMQ 3.9.16 on Erlang 24.3.3
Maintenance status
Node: rabbit@rabbitmq-1, status: not under maintenance
Node: rabbit@rabbitmq-2, status: not under maintenance
Node: rabbit@rabbitmq-3, status: not under maintenance
Alarms
(none)
Network Partitions
(none)
Listeners
Node: rabbit@rabbitmq-1, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-1, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-1, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-2, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-2, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-2, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-3, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-3, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-3, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Feature flags
Flag: drop_unroutable_metric, state: enabled
Flag: empty_basic_get_metric, state: enabled
Flag: implicit_default_bindings, state: enabled
Flag: maintenance_mode_status, state: enabled
Flag: quorum_queue, state: enabled
Flag: stream_queue, state: enabled
Flag: user_limits, state: enabled
Flag: virtual_host_metadata, state: enabled
# 然后再把 rabbitmq-2 变更为内存节点:
[root@rabbitmq-2 ~]# rabbitmqctl stop_app
[root@rabbitmq-2 ~]# rabbitmqctl change_cluster_node_type ram
# 中间可能会有错误但是可以忽略
[root@rabbitmq-2 ~]# rabbitmqctl start_app
Starting node rabbit@rabbitmq-2 ...
# 再次查看集群
[root@rabbitmq-1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-1 ...
Basics
Cluster name: rabbit@rabbitmq-1
Disk Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-3
RAM Nodes
rabbit@rabbitmq-2 # RAM节点就变了
Running Nodes
rabbit@rabbitmq-1
rabbit@rabbitmq-2
rabbit@rabbitmq-3
Versions
rabbit@rabbitmq-1: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-2: RabbitMQ 3.9.16 on Erlang 24.3.3
rabbit@rabbitmq-3: RabbitMQ 3.9.16 on Erlang 24.3.3
Maintenance status
Node: rabbit@rabbitmq-1, status: not under maintenance
Node: rabbit@rabbitmq-2, status: not under maintenance
Node: rabbit@rabbitmq-3, status: not under maintenance
Alarms
(none)
Network Partitions
(none)
Listeners
Node: rabbit@rabbitmq-1, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-1, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-1, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-2, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-2, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-2, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Node: rabbit@rabbitmq-3, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@rabbitmq-3, interface: [::], port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@rabbitmq-3, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Feature flags
Flag: drop_unroutable_metric, state: enabled
Flag: empty_basic_get_metric, state: enabled
Flag: implicit_default_bindings, state: enabled
Flag: maintenance_mode_status, state: enabled
Flag: quorum_queue, state: enabled
Flag: stream_queue, state: enabled
Flag: user_limits, state: enabled
Flag: virtual_host_metadata, state: enabled
5:登录后台

上面配置 RabbitMQ 默认集群模式,但并不保证队列的高可用性,尽管交换机、绑定这些可以复制到集群里的任何一个节点,但是队列内容不会复制,虽然该模式解决一部分节点压力,但队列节点宕机直接导致该队列无法使用,只能等待重启,所以要想在队列节点宕机或故障也能正常使用,就要复制队列内容到集群里的每个节点,也就引入了镜像队列的概念。
6:镜像队列
6.1:概念
镜像队列可以同步 queue 和 message,当主 queue 挂掉,从 queue 中会有一个变为主 queue 来接替工作。
镜像队列是基于普通的集群模式的, 所以你还是得先配置普通集群, 然后才能设置镜像队列。
镜像队列设置后,会分一个主节点和多个从节点,如果主节点宕机,从节点会有一个选为主节点,原先的主节点起来后会变为从节点。
queue 和 message 虽然会存在所有镜像队列中,但客户端读取时不论物理面连接的主节点还是从节点,都是从主节点读取数据,然后主节点再将 queue 和 message 的状态同步给从节点,因此多个客户端连接不同的镜像队列不会产生同一 message 被多次接受的情况。
6.2:配置
在普通集群的中任意节点启用策略,策略会自动同步到集群节点
命令格式
# set_policy [-p vhostpath] {name} {pattern} {definition} [priority]
在任意一个节点上执行
[root@rabbitmq-1 ~]# rabbitmqctl set_policy -p / ha-allqueue "^isj" '{"ha-mode":"all"}'
Setting policy "ha-allqueue" for pattern "^isj" to "{"ha-mode":"all"}" with priority "0" for vhost "/" ...
注意:"^isj" 这个规则要根据自己实际情况修改,这个是指同步”isj” 开头的队列名称,配置时使用的应用于所有队列,所以表达式为”^”。
7:反向代理
这里我我们可以选择使用Nginx进行一个反向代理实现一个负载均衡的效果
添加代理配置如下
# nginx.conf配置
[root@virtual_host ~]# cat /etc/nginx/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
include /etc/nginx/conf.d/*.conf;
# MQ代理配置
[root@virtual_host ~]# cat /etc/nginx/conf.d/rabbitmq.conf
stream {
upstream rabbitmq {
server 10.0.0.10:5672 max_fails=2 fail_timeout=3s weight=2;
server 10.0.0.11:5672 max_fails=2 fail_timeout=3s weight=2;
server 10.0.0.12:5672 max_fails=2 fail_timeout=3s weight=2;
}
server {
listen 5672;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass rabbitmq;
}
}
[root@virtual_host ~]# nginx
[root@virtual_host ~]# ss -lnt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:5672 *:*
LISTEN 0 128 *:111 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 128 [::]:111 [::]:*
LISTEN 0 128 [::]:22 [::]:*
这样,我们连接MQ的时候只需要连接Nginx就可以了,若Nginx并发不足,我们还可以做Nginx的高可用即可。