RabbitMQ集群

rabbitMQ集群有两种模式:

第一种 普通模式:对于Queue来说,消息实体只存在于其中的一个节点,A/B两个节点仅有相同的元数据(队列结构)。也就是说数据存在于集群中某个节点,我们从另一个节点获取的时候是该节点和存储数据的节点临时进行传输。可以理解为A/B,搭建集群,数据存到A,我们从节点B可以获取到是B节点临时和A节点建立了数据通道从A获取数据,假设A节点宕机,则数据丢失。这种模式的话没有实现高可用。

第二种 镜像模式:也称为HA高可用模式,与普通集群模式区别 主要是消息实体会主动在镜像节点间同步数据,而不是只存储数据元信息。这种模式保证了HA,但是降低了系统性能,如果镜像队列过多,在消息大量进来的情况下,集群内部的网络带宽会被这种内部同步消耗掉,这种适用于可靠性要求较高的场景中。

下面研究镜像集群模式的搭建,还是以docker的形式进行搭建。

1.拉取镜像

docker pull hub.c.163.com/library/rabbitmq:management

2.创建容器,启动两个mq进程

1.容器1

$ docker run -d --hostname rabbitmq01 --name rabbitmqCluster01 -p 15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitmqCookie' hub.c.163.com/library/rabbitmq:management
df45f88945b572ed8b23c8998db8819e7c7826ded2058ea235c2f04f775f4a2c

2.容器2

$ docker run -d --hostname rabbitmq02 --name rabbitmqCluster02  -p 15673:15672 -p 5673:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitmqCookie'  --link rabbitmqCluster01:rabbitmq01 hub.c.163.com/library/rabbitmq:management
1f18cbceb309d9ac3f723563151d81f18955b1e5534f23222b3e92cba57dbb86

参数解释:

-d: 后台运行容器,并返回容器ID;
--hostname rabbitmq02  指定容器的hostname
--name="rabbitmqCluster02": 为容器指定一个名称;
-p 外部端口:内部端口,是将端口做映射。15672是管理界面端口,5672是客户端通讯接口
-e  设置环境变量
--link=[]: 添加链接到另一个容器;也就是使得两个容器可以通信

这里解释下。-e RABBITMQ_ERLANG_COOKIE='rabbitmqCookie' 是设置环境变量。ErlangCookie是保证不同节点间可以互相通信的密钥,要保证不同节点间可以互相通信必须保证共享相同的Erlang Cookie,在容器内部的话是放在/var/lib/rabbitmq/.erlang.cookie

进入容器内部查看:

root@rabbitmq02:/# cat /var/lib/rabbitmq/.erlang.cookie
rabbitmqCookie

3.启动后应该通过15672端口和15673端口都可以访问到management控制台

4.容器节点加入集群

1.对节点1设置

(1)进入容器1,也就是rabbitmq01

$ docker exec -it df bash

(2) 停止服务、清数据、重启

root@rabbitmq01:/# rabbitmqctl stop_app  #停服务
Stopping rabbit application on node rabbit@rabbitmq01
root@rabbitmq01:/# rabbitmqctl reset  #清掉数据
Resetting node rabbit@rabbitmq01
root@rabbitmq01:/# rabbitmqctl start_app  重启
Starting node rabbit@rabbitmq01

2.对节点2设置

(1)进入容器

$ docker exec -it 1f /bin/bash

(2)加入集群

root@rabbitmq02:/# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@rabbitmq02
root@rabbitmq02:/# rabbitmqctl reset
Resetting node rabbit@rabbitmq02
root@rabbitmq02:/# rabbitmqctl join_cluster --ram rabbit@rabbitmq01
Clustering node rabbit@rabbitmq02 with rabbit@rabbitmq01
root@rabbitmq02:/# rabbitmqctl start_app
Starting node rabbit@rabbitmq02

rabbitmqctl join_cluster --ram rabbit@rabbitmq01 是加入集群,rabbitmq01 是另一个节点的hostname。

补充:如果还有第三个节点加入集群,也是用上面的方式加入集群

5.到管理端查看,可以看到节点信息

6. 增加一个策略,设置集群镜像模式

  可以到控制台设置,也可以到界面设置。这里在控制台设置:

root@rabbitmq01:/# rabbitmqctl set_policy ha "^" '{"ha-mode":"all"}'
Setting policy "ha" for pattern "^" to "{\"ha-mode\":\"all\"}" with priority "0"

到界面查看:

  到此集群搭建完成。

7.Springboot连接集群

只需要修改连接地址就可以了,如下:

#cluster
spring.rabbitmq.addresses=192.168.99.100:5672,192.168.99.100:5673
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

 8. 补充: 三个集群节点补充

1. 新起三个docker 容器

xxx@A022296-NC01 MINGW64 ~
$ docker run -d --hostname rabbitmq01 --name rabbitmqCluster01 -p 15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitmqCookie' hub.c.163.com/library/rabbitmq:management
932b8518e782ae7a4ef1e85b9210d205af180609bc0974699c805f9015d37fb5

xxx@A022296-NC01 MINGW64 ~
$ docker run -d --hostname rabbitmq02 --name rabbitmqCluster02  -p 15673:15672 -p 5673:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitmqCookie'  --link rabbitmqCluster01:rabbitmq01 hub.c.163.com/library/rabbitmq:management
c6f5a0a8561024b352abfded4332a8b954f555672120f9c856ff5093373ce48b

xxx@A022296-NC01 MINGW64 ~
$ docker run -d --hostname rabbitmq03 --name rabbitmqCluster03  -p 15674:15672 -p 5674:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitmqCookie'  --link rabbitmqCluster01:rabbitmq01 --link rabbitmqCluster02:rabbitmq02 hub.c.163.com/library/rabbitmq:management
ae84596ed05e39d564f7b22270dd2c96fa2fd6c072ee01897cba84116e1fc18e

2. 第二个加入集群

$ docker exec -it c6 bash
root@rabbitmq02:/# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@rabbitmq02
root@rabbitmq02:/# rabbitmqctl reset
Resetting node rabbit@rabbitmq02
root@rabbitmq02:/# rabbitmqctl join_cluster --ram rabbit@rabbitmq02
Clustering node rabbit@rabbitmq02 with rabbit@rabbitmq01
root@rabbitmq02:/#  rabbitmqctl start_app
Starting node rabbit@rabbitmq02

3. 第三个加入集群

$ docker exec -it ae bash
root@rabbitmq03:/# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@rabbitmq03
root@rabbitmq03:/# rabbitmqctl reset
Resetting node rabbit@rabbitmq03
root@rabbitmq03:/# rabbitmqctl join_cluster --ram rabbit@rabbitmq02
Clustering node rabbit@rabbitmq03 with rabbit@rabbitmq02
root@rabbitmq03:/# rabbitmqctl start_app
Starting node rabbit@rabbitmq03

4. 查看集群状态:

root@rabbitmq03:/# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq03
[{nodes,[{disc,[rabbit@rabbitmq01]},
         {ram,[rabbit@rabbitmq03,rabbit@rabbitmq02]}]},
 {running_nodes,[rabbit@rabbitmq02,rabbit@rabbitmq01,rabbit@rabbitmq03]},
 {cluster_name,<<"rabbit@rabbitmq01">>},
 {partitions,[]},
 {alarms,[{rabbit@rabbitmq02,[]},
          {rabbit@rabbitmq01,[]},
          {rabbit@rabbitmq03,[]}]}]

5. 关于节点类型 

  在集群中声明(declare)创建exchange queue binding,这类操作要等到所有的节点都完成创建才会返回:如果是内存节点就要修改内存数据,如果是disk node 就要等待写磁盘,节点过多这里的速度就会被大大的拖慢。只要有一个节点是Disc Node 就能提供条件把集群元数据写到磁盘,RabbitMQ的确也是这样要求的:集群中只要有一个disk node就可以,其它的都可以是RAM node.节点加入或退出集群一定至少要通知集群中的一个disk node,来记录这种变动.
6. 总结:

  现在搭建的集群是默认的普通集群,集群中节点可以共享集群中的exchange,routingKey和queue,但是queue中的消息只保存在首次声明queue的节点中。通过其他节点获取队列消息的时候是节点从队列所在节点获取到自己内存中然后返回给客户端。因为queue中的消息只保存在首次声明queue的节点中,这样就个问题:如果某一个node节点挂掉了,那么只能等待该节点重新连接才能继续处理该节点内的消息(如果没有设置持久化的话,节点挂掉后消息会直接丢失)。测试可以创建一个队列, 创建的时候需要选择所在的节点,发送一些消息后让该节点下线, 会导致该队列不可用。 也可以到每个集群节点内部查看队列数量:

root@rabbitmq01:~/mnesia/rabbit@rabbitmq01# pwd
/var/lib/rabbitmq/mnesia/rabbit@rabbitmq01
root@rabbitmq01:~/mnesia/rabbit@rabbitmq01# ls -l
total 108
-rw-r--r-- 1 rabbitmq rabbitmq   160 Nov 22 09:07 DECISION_TAB.LOG
-rw-r--r-- 1 rabbitmq rabbitmq    96 Nov 22 09:07 LATEST.LOG
-rw-r--r-- 1 rabbitmq rabbitmq    79 Nov 22 09:04 cluster_nodes.config
drwxr-xr-x 2 rabbitmq rabbitmq  4096 Nov 22 09:04 msg_store_persistent
drwxr-xr-x 2 rabbitmq rabbitmq  4096 Nov 22 09:04 msg_store_transient
-rw-r--r-- 1 rabbitmq rabbitmq    57 Nov 22 09:04 nodes_running_at_shutdown
drwxr-xr-x 3 rabbitmq rabbitmq  4096 Nov 22 08:29 queues
-rw-r--r-- 1 rabbitmq rabbitmq  1323 Nov 22 09:04 rabbit_durable_exchange.DCD
-rw-r--r-- 1 rabbitmq rabbitmq   250 Nov 22 09:04 rabbit_durable_queue.DCD
-rw-r--r-- 1 rabbitmq rabbitmq   329 Nov 22 09:07 rabbit_durable_queue.DCL
-rw-r--r-- 1 rabbitmq rabbitmq   230 Nov 22 09:04 rabbit_durable_route.DCD
-rw-r--r-- 1 rabbitmq rabbitmq   163 Nov 22 09:04 rabbit_runtime_parameters.DCD
-rw-r--r-- 1 rabbitmq rabbitmq     3 Nov 22 09:04 rabbit_serial
-rw-r--r-- 1 rabbitmq rabbitmq   227 Nov 22 09:04 rabbit_user.DCD
-rw-r--r-- 1 rabbitmq rabbitmq   190 Nov 22 09:04 rabbit_user_permission.DCD
-rw-r--r-- 1 rabbitmq rabbitmq   131 Nov 22 09:04 rabbit_vhost.DCD
-rw-r--r-- 1 rabbitmq rabbitmq  5464 Nov 22 09:04 recovery.dets
-rw-r--r-- 1 rabbitmq rabbitmq 25778 Nov 22 08:33 schema.DAT
-rw-r--r-- 1 rabbitmq rabbitmq   285 Nov 22 03:06 schema_version

  可以到queues 目录下查看相关队列信息。也可以到每个主机上执行下面命令查看队列:

rabbitmqctl list_queues --local

7. 配置镜像队列

  镜像队列是在普通集群搭建后,通过设置同步策略来实现的。在任何一台机子执行下面命令:

rabbitmqctl set_policy ha-all "^my" '{"ha-mode":"all","ha-sync-mode":"automatic"}'
# rabbitmqctl set_policy [-p Vhost] Name Pattern Definition [Priority]
# ha-all:为策略名称;
# ^my:为匹配符,只有一个^代表匹配所有,^abc为匹配名称以abc开头的queue或exchange;
# ha-mode:为同步模式,一共3种模式:
#    ①all-所有(所有的节点都同步消息),
#    ②exctly-指定节点的数目(需配置ha-params参数,此参数为int类型比如2,在集群中随机抽取2个节点同步消息)
#    ③nodes-指定具体节点(需配置ha-params参数,此参数为数组类型比如["rabbit@rabbitmq1","rabbit@rabbitmq2"],明确指定在这两个节点上同步消息)。
# ha-sync-mode:进行队列中消息的同步方式,有效值为automatic和manual

或者web中Admin -> Policies 设置

查看策略:

root@rabbitmq02:~/mnesia# rabbitmqctl list_policies
Listing policies
/       ha-all  all     ^       {"ha-mode":"all","ha-sync-mode":"automatic"}    0

 

 8. 测试新建一个队列myqueue, 可以看到会采用上面的策略, 并且在node1 挂掉后会自动切换node2 继续提供服务。

 

参考: https://www.rabbitmq.com/clustering.html

 

posted @ 2020-11-08 15:15  QiaoZhi  阅读(809)  评论(1编辑  收藏  举报