介绍RabbitMQ中,如何搭建普通集群与镜像集群。
机器准备
这里我们建立一个3台机器组成的集群,事先先在3台机器上安装好RabbitMQ服务。
机器IP:
10.100.3.106
10.100.2.234
10.100.2.235
普通集群
1.概要
每台物理机是一个节点,消息实体只保存在一个节点上。
当节点出现故障时:
- 消息持久化:当节点恢复时,可获取此节点未消费的消息
- 消息未持久化:则会丢失此节点上未消费的消息
当从A节点消费B节点上消息时,会通过消费者消费的队列找到该队列所在的节点,从此节点获取获取后,返回给消费者。
节点内部元数据
- 队列元数据:队列名称和它们的属性(是否可持久化,是否自动删除)
- 交换器元数据:交换器名称,类型和属性(是否持久化等)
- 绑定元数据:一张简单的表格展示了如何将消息路由到队列
- vhost元数据:为虚拟主机内的队列,交换器和绑定提供命名空间和安全属性
队列
- 队列的所有者节点:存储队列的元数据、状态、内容
- 非队列的所有者节点:保存队列的元数据和指向队列所有者的指针
队列类似于节点上运行的进程,每个进程拥有自己的进程ID(集群中的Erlang地址),信道将消息进行匹配后,会建立到队列PID的连接,然后将消息发送过去。
交换器
不同于队列拥有自己的进程,交换器只是队列与路由键的关系表,当消息发送到交换器时,信道会将消息上的路由键与交换器的关系表进行匹配,从而决定将消息路由到哪个队列。
由于交换器只是一张关系表,所以交换器会在整个集群中进行同步复制,集群中每个节点都拥有每个交换器的信息,节点故障时可以不用重新声明交换器。
节点类型
- 内存节点(ram):队列、交换机、绑定、用户、权限、vhost的元数据都存储在内存中
- 磁盘节点(disk):元数据存放在磁盘上。一个集群至少要有一个磁盘节点,用来保存集群的配置信息
正常使用时都使用磁盘节点,除非需要改进有高队列、交换或绑定的性能集群(将部分节点调整为内存节点)。RAM节点并不提供更高的消息速率。
磁盘节点适合队列长存服务器的应用;内存节点适合RPC等频繁创建或销毁队列的应用。
2.hosts配置
在每个主机的/etc/hosts
文件中加入如下配置,便于节点间访问:
#rabbitmq_node1
10.100.3.106 DEV-HROEx64
#rabbitmq_node2
10.100.2.234 DEV-mHRO
#rabbitmq_node3
10.100.2.235 DEV-mHRO64
如果需要主机名比较一致,可以修改主机名。
[root@DEV-HROEx64 ~]# vim /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=DEV-HROEx64
#HOSTNAME=rabbitmq_node1
[root@DEV-HROEx64 ~]# reboot
3.Erlang Cookie设置
RabbitMQ节点之间和命令行工具(如rabbitmqctl)是使用Cookie来确认是否允许互相通信的。对于多个能够通信的节点必须要有相同的Erlang Cookie。Cookie是一组随机的数字+字母的字符串,最大为255字节。
当Erlang Cookie文件不存在时,Erlang VM将尝试在RabbitMQ服务器启动时创建一个随机生成的值。
.erlang.cookie
文件一般在如下2个地方:
1. /var/lib/rabbitmq/.erlang.cookie
2. $HOME/.erlang.cookie
#这里我们将rabbitmq_node2与rabbitmq_node3上的cookie,都使用rabbitmq_node1上的cookie
[root@DEV-mHRO otp_src_20.3]# scp -r root@rabbitmq_node1:/root/.erlang.cookie /root/.erlang.cookie
[root@DEV-mHRO64 bmsource]# scp -r root@rabbitmq_node1:/root/.erlang.cookie /root/.erlang.cookie
#确认一下3台机器上的cookie是否一致
#rabbitmq_node1
# cat /root/.erlang.cookie
ISIHBJETBSGTLNHVJLTQ
#rabbitmq_node2
# cat /root/.erlang.cookie
ISIHBJETBSGTLNHVJLTQ
#rabbitmq_node3
# cat /root/.erlang.cookie
ISIHBJETBSGTLNHVJLTQ
4.重启RabbitMQ服务
#启动RabbitMQ服务
#rabbitmq_node1
[root@DEV-HROEx64 ~]# rabbitmq-server -detached
#rabbitmq_node2
[root@DEV-HROEx64 ~]# rabbitmq-server -detached
#rabbitmq_node3
[root@DEV-HROEx64 ~]# rabbitmq-server -detached
#查看每个节点集群状态
#rabbitmq_node1
[root@DEV-HROEx64 ~]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@DEV-HROEx64'
[{nodes,[{disc,['rabbit@DEV-HROEx64']}]},
{running_nodes,['rabbit@DEV-HROEx64']},
{cluster_name,<<"rabbit@DEV-HROEx64">>},
{partitions,[]},
{alarms,[{'rabbit@DEV-HROEx64',[]}]}]
#rabbitmq_node2
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@DEV-mHRO'
[{nodes,[{disc,['rabbit@DEV-mHRO']}]},
{running_nodes,['rabbit@DEV-mHRO']},
{cluster_name,<<"rabbit@DEV-mHRO">>},
{partitions,[]},
{alarms,[{'rabbit@DEV-mHRO',[]}]}]
#rabbitmq_node3
[root@DEV-mHRO64 bmsource]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@DEV-mHRO64'
[{nodes,[{disc,['rabbit@DEV-mHRO64']}]},
{running_nodes,['rabbit@DEV-mHRO64']},
{cluster_name,<<"rabbit@DEV-mHRO64">>},
{partitions,[]},
{alarms,[{'rabbit@DEV-mHRO64',[]}]}]
5.创建集群
通过将rabbitmq_node2与rabbitmq_node3加入到rabbitmq_node1中,我们可以搭建一个集群。
在rabbitmq-server启动时,会一起启动节点和应用,它预先设置RabbitMQ应用为standalone模式。要将一个节点加入到现有的集群中,需要停止这个应用并将节点设置为原始状态,然后就为加入集群准备好了。如果使用rabbitmqctl stop
,应用和节点都将被关闭,而使用rabbitmqctl stop_app
仅仅关闭应用。
#rabbitmq_node2加入到rabbitmq_node1
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl stop_app
Stopping rabbit application on node 'rabbit@DEV-mHRO'
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl join_cluster rabbit@DEV-HROEx64
Clustering node 'rabbit@DEV-mHRO' with 'rabbit@DEV-HROEx64'
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl start_app
Starting node 'rabbit@DEV-mHRO'
#rabbitmq_node3加入到rabbitmq_node1
[root@DEV-mHRO64 bmsource]# rabbitmqctl stop_app
Stopping rabbit application on node 'rabbit@DEV-mHRO64'
You have mail in /var/spool/mail/root
[root@DEV-mHRO64 bmsource]# rabbitmqctl join_cluster rabbit@DEV-HROEx64
Clustering node 'rabbit@DEV-mHRO64' with 'rabbit@DEV-HROEx64'
[root@DEV-mHRO64 bmsource]# rabbitmqctl start_app
Starting node 'rabbit@DEV-mHRO64'
#查看每个节点集群状态
#rabbitmq_node1
[root@DEV-HROEx64 ~]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@DEV-HROEx64'
[{nodes,[{disc,['rabbit@DEV-HROEx64','rabbit@DEV-mHRO','rabbit@DEV-mHRO64']}]},
{running_nodes,['rabbit@DEV-mHRO64','rabbit@DEV-mHRO','rabbit@DEV-HROEx64']},
{cluster_name,<<"rabbit@DEV-HROEx64">>},
{partitions,[]},
{alarms,[{'rabbit@DEV-mHRO64',[]},
{'rabbit@DEV-mHRO',[]},
{'rabbit@DEV-HROEx64',[]}]}]
#rabbitmq_node2
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@DEV-mHRO'
[{nodes,[{disc,['rabbit@DEV-HROEx64','rabbit@DEV-mHRO','rabbit@DEV-mHRO64']}]},
{running_nodes,['rabbit@DEV-mHRO64','rabbit@DEV-HROEx64','rabbit@DEV-mHRO']},
{cluster_name,<<"rabbit@DEV-HROEx64">>},
{partitions,[]},
{alarms,[{'rabbit@DEV-mHRO64',[]},
{'rabbit@DEV-HROEx64',[]},
{'rabbit@DEV-mHRO',[]}]}]
#rabbitmq_node3
[root@DEV-mHRO64 bmsource]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@DEV-mHRO64'
[{nodes,[{disc,['rabbit@DEV-HROEx64','rabbit@DEV-mHRO','rabbit@DEV-mHRO64']}]},
{running_nodes,['rabbit@DEV-HROEx64','rabbit@DEV-mHRO','rabbit@DEV-mHRO64']},
{cluster_name,<<"rabbit@DEV-HROEx64">>},
{partitions,[]},
{alarms,[{'rabbit@DEV-HROEx64',[]},
{'rabbit@DEV-mHRO',[]},
{'rabbit@DEV-mHRO64',[]}]}]
上面集群中各节点都是磁盘节点,如果希望节点是内存节点,可以参考如下设置方法。
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl stop_app
Stopping rabbit application on node 'rabbit@DEV-mHRO'
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl join_cluster --ram rabbit@DEV-HROEx64
Clustering node 'rabbit@DEV-mHRO' with 'rabbit@DEV-HROEx64'
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl start_app
Starting node 'rabbit@DEV-mHRO'
#查看集群状态
[root@DEV-HROEx64 ~]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@DEV-HROEx64'
[{nodes,[{disc,['rabbit@DEV-HROEx64','rabbit@DEV-mHRO64']},
{ram,['rabbit@DEV-mHRO']}]},
{running_nodes,['rabbit@DEV-mHRO','rabbit@DEV-mHRO64','rabbit@DEV-HROEx64']},
{cluster_name,<<"rabbit@DEV-HROEx64">>},
{partitions,[]},
{alarms,[{'rabbit@DEV-mHRO',[]},
{'rabbit@DEV-mHRO64',[]},
{'rabbit@DEV-HROEx64',[]}]}]
如果原先集群的挂载的节点(rabbit@DEV-HROEx64)从集群(rabbit@DEV-HROEx64)脱离了,在重新挂载到集群时,会报如下错误。
[root@DEV-HROEx64 /]# rabbitmqctl join_cluster rabbit@DEV-HROEx64
Clustering node 'rabbit@DEV-HROEx64' with 'rabbit@DEV-HROEx64'
Error: cannot_cluster_node_with_itself
可将节点挂载到集群中的任意有效节点(rabbit@DEV-mHRO),则节点也会进入到集群中。
[root@DEV-HROEx64 /]# rabbitmqctl join_cluster rabbit@DEV-mHRO
6.从集群中移除节点
6.1.在要脱离的节点机器上
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl stop_app
Stopping rabbit application on node 'rabbit@DEV-mHRO'
You have mail in /var/spool/mail/root
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl reset
Resetting node 'rabbit@DEV-mHRO'
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl start_app
Starting node 'rabbit@DEV-mHRO'
6.2.在其他节点机器上
#模拟rabbitmq_node2没服务了
[root@DEV-mHRO otp_src_20.3]# rabbitmqctl stop_app
Stopping rabbit application on node 'rabbit@DEV-mHRO'
#在rabbitmq_node1上移除rabbitmq_node2
[root@DEV-HROEx64 ~]# rabbitmqctl forget_cluster_node rabbit@DEV-mHRO
Removing node 'rabbit@DEV-mHRO' from cluster
7.web管理端查看集群状态
7.1.新增集群账号
在集群中任意一个节点上,新增一个可用账号。
#rabbitmq_node1添加账号
[root@DEV-HROEx64 ~]# rabbitmqctl add_user admin admin
[root@DEV-HROEx64 ~]# rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
Setting permissions for user "admin" in vhost "/"
[root@DEV-HROEx64 ~]# rabbitmqctl set_user_tags admin administrator
Setting tags for user "admin" to [administrator]
7.2.开启rabbitmq_management插件
为了监控数据的准确性需要开启每台服务器的rabbitmq_management插件。
#rabbitmq_node1
[root@DEV-HROEx64 ~]# rabbitmq-plugins enable rabbitmq_management
#rabbitmq_node2
[root@DEV-mHRO ~]# rabbitmq-plugins enable rabbitmq_management
#rabbitmq_node3
[root@DEV-mHRO64 ~]# rabbitmq-plugins enable rabbitmq_management
7.3.登录web管理端查看集群状态
8.集群使用测试
为了验证集群的可用性,我们将消息发送到rabbitmq_node1
上的队列,在rabbitmq_node2
与rabbitmq_node3
获取队列里的消息。
8.1.测试代码
8.2.web管理端信息
镜像集群
1.概要
与普通集群不同的是,镜像集群会把队列结构与消息存放在多个节点,消息会在镜像节点间同步,从而实现高可用的架构。
由于需要进行节点间的同步,所以镜像集群在性能方面会降低;如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大量消耗。所以这种模式应用于可靠性要求较高的场合中。
Tips:如果将消息存储置于SSD的话,就可以极大提升持久化消息通信的性能。
2.如何配置
镜像功能,需要通过RabbitMQ策略来实现。策略可以控制一个集群内某个vhost中的队列与交换器的镜像行为。在集群的任意节点创建策略,策略都会同步到其他节点。
- Pattern:正则表达式,【\^】代表所有队列,【\^test】代表test开头的队列 - HA mode:可选【all,exactly,nodes】,正常都使用【all】,如果使用【exactly,nodes】还需要配置HA params
3.环境准备
镜像集群是普通集群的扩展使用,所以可以参照普通集群的搭建方式事先进行搭建。
4.创建镜像策略
4.1.web管理端
4.2.cli命令行
[root@DEV-HROEx64 ~]# rabbitmqctl set_policy -p / test_policy2 '^' '{"ha-mode":"all"}'
Setting policy "test_policy2" for pattern "^" to "{\"ha-mode\":\"all\"}" with priority "0"
4.3.策略查看
检查3台机器上的策略已经同步为一致了。
#rabbitmq_node1
[root@DEV-HROEx64 ~]# rabbitmqctl list_policies
Listing policies
/ test_policy2 all ^ {"ha-mode":"all"} 0
/ test_policy all ^ {"ha-mode":"all"} 0
#rabbitmq_node2
[root@DEV-mHRO ~]# rabbitmqctl list_policies
Listing policies
/ test_policy2 all ^ {"ha-mode":"all"} 0
/ test_policy all ^ {"ha-mode":"all"} 0
#rabbitmq_node3
[root@DEV-mHRO64 ~]# rabbitmqctl list_policies
Listing policies
/ test_policy2 all ^ {"ha-mode":"all"} 0
/ test_policy all ^ {"ha-mode":"all"} 0
5.镜像集群使用测试
测试代码同上面普通集群的测试代码。