RabbitMQ学习-集群

cluster

Posted by zwtisme on May 18, 2018

介绍RabbitMQ中,如何搭建普通集群与镜像集群。

机器准备

这里我们建立一个3台机器组成的集群,事先先在3台机器上安装好RabbitMQ服务。

机器IP:
10.100.3.106
10.100.2.234
10.100.2.235

普通集群

1.概要

每台物理机是一个节点,消息实体只保存在一个节点上。

当节点出现故障时:

  • 消息持久化:当节点恢复时,可获取此节点未消费的消息
  • 消息未持久化:则会丢失此节点上未消费的消息

当从A节点消费B节点上消息时,会通过消费者消费的队列找到该队列所在的节点,从此节点获取获取后,返回给消费者。

节点内部元数据
  • 队列元数据:队列名称和它们的属性(是否可持久化,是否自动删除)
  • 交换器元数据:交换器名称,类型和属性(是否持久化等)
  • 绑定元数据:一张简单的表格展示了如何将消息路由到队列
  • vhost元数据:为虚拟主机内的队列,交换器和绑定提供命名空间和安全属性
队列
  • 队列的所有者节点:存储队列的元数据、状态、内容
  • 非队列的所有者节点:保存队列的元数据和指向队列所有者的指针

队列类似于节点上运行的进程,每个进程拥有自己的进程ID(集群中的Erlang地址),信道将消息进行匹配后,会建立到队列PID的连接,然后将消息发送过去。

image

交换器

不同于队列拥有自己的进程,交换器只是队列与路由键的关系表,当消息发送到交换器时,信道会将消息上的路由键与交换器的关系表进行匹配,从而决定将消息路由到哪个队列。

由于交换器只是一张关系表,所以交换器会在整个集群中进行同步复制,集群中每个节点都拥有每个交换器的信息,节点故障时可以不用重新声明交换器。

节点类型
  • 内存节点(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管理端查看集群状态

image

8.集群使用测试

为了验证集群的可用性,我们将消息发送到rabbitmq_node1上的队列,在rabbitmq_node2rabbitmq_node3获取队列里的消息。

8.1.测试代码

生产-node1

消费-node2

消费-node3

8.2.web管理端信息

image

image

镜像集群

1.概要

与普通集群不同的是,镜像集群会把队列结构与消息存放在多个节点,消息会在镜像节点间同步,从而实现高可用的架构。

由于需要进行节点间的同步,所以镜像集群在性能方面会降低;如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大量消耗。所以这种模式应用于可靠性要求较高的场合中。

Tips:如果将消息存储置于SSD的话,就可以极大提升持久化消息通信的性能。

2.如何配置

镜像功能,需要通过RabbitMQ策略来实现。策略可以控制一个集群内某个vhost中的队列与交换器的镜像行为。在集群的任意节点创建策略,策略都会同步到其他节点。

- Pattern:正则表达式,【\^】代表所有队列,【\^test】代表test开头的队列 - HA mode:可选【all,exactly,nodes】,正常都使用【all】,如果使用【exactly,nodes】还需要配置HA params

3.环境准备

镜像集群是普通集群的扩展使用,所以可以参照普通集群的搭建方式事先进行搭建。

4.创建镜像策略

4.1.web管理端

image

image

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.镜像集群使用测试

测试代码同上面普通集群的测试代码。

image

image

参考资料

普通集群

镜像集群