说明:集群,不管是Redis集群,还是MQ集群,都是为了提高系统的可用性,使系统不至于因为Redis、MQ宕机而崩溃。本文介绍RabbitMQ集群搭建,RabbitMQ集群分为以下三类:
-
普通集群
-
镜像集群
-
仲裁队列
普通集群
普通集群下,节点之间并不会进行数据同步,而是节点之间存在引用,当消费者绑定的队列(one.queue1),在当前这个节点(mq3)中不存在时,如果该节点关联了该队列所在的节点(mq1),会去该节点拉取消息,并返回。
节点之间的通信是依靠Erlang cookie实现的,当集群中的节点拥有相同的Erlang cookie,则这些节点可以相互通信。Erlang cookie是长度最多255的字母数字字符。
结构图:
搭建
第一步:获取Cookie
输入下面的命令,获取当前单机RabbitMQ的Cookie值,后面把这个值当做集群MQ中每个节点的Cookie;
docker exec -it mq cat /var/lib/rabbitmq/.erlang.cookie
Cookie值为前面的这一段:SKPRVQBTSMEJURVKVQGH
顺便停掉当前运行中的RabbitMQ
docker rm -f mq
第二步:准备配置文件
在/tem目录下,创建一个关于RabbitMQ的配置文件(rabbitmq.conf),内容如下:
loopback_users.guest = false
listeners.tcp.default = 5672
cluster_formation.peer_discovery_backend = rabbit_peer_discovery_classic_config
cluster_formation.classic_config.nodes.1 = rabbit@mq1
cluster_formation.classic_config.nodes.2 = rabbit@mq2
cluster_formation.classic_config.nodes.3 = rabbit@mq3
第三步:创建cookie文件
在/tem目录下,创建一个文件,用于记录Cookie信息,并设置cookie文件的权限为600,即只能被管理员读写;
# 创建cookie文件
touch .erlang.cookie
# 写入cookie
echo "cookie值" > .erlang.cookie
# 修改cookie文件的权限
chmod 600 .erlang.cookie
第四步:创建目录
准备三个目录,搭建三个节点的集群,分别把配置文件,cooke文件拷贝到这三个目录里;
mkdir mq1 mq2 mq3
cp rabbitmq.conf mq1
cp rabbitmq.conf mq2
cp rabbitmq.conf mq3
cp .erlang.cookie mq1
cp .erlang.cookie mq2
cp .erlang.cookie mq3
第五步:启动
先创建一个网络
docker network create mq-net
分别启动这三个节点,账号、密码相同,名称分别为:mq1、mq2、mq3
程序端口号分别是:8071、8072、8073;
管理平台端口号分别是:8081、8082、8083;
docker run -d --net mq-net \
-v ${PWD}/mq1/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \
-v ${PWD}/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
-e RABBITMQ_DEFAULT_USER=root \
-e RABBITMQ_DEFAULT_PASS=123456 \
--name 节点名称 \
--hostname 节点名称 \
-p 程序端口:5672 \
-p 管理平台端口:15672 \
rabbitmq:3.8-management
第六步:测试
打开这三个管理平台,如果使用的是云服务,需要开放对应的端口;如果使用的是虚拟机,可直接关闭防火墙;
可以看到其他节点的信息,说明搭建完成;
第七步:使用
在第一个节点(8081)里面创建一个队列,队列内添加一条信息,如下:
在第二个节点(8082)中,可以查看到队列信息和消息的内容,已经达到了集群的效果;
可是此时,把创建这个队列的节点8081关闭,再查看另外节点的情况,另外节点可以看到队列信息,但是不能查看队列的消息内容;
小结
在普通集群下,如果各个节点都在线,可以访问任意一个节点,消费到任何队列的消息。但是因为节点之间没有备份数据,某节点下线后,其他节点就不能访问到该节点的消息。普通镜像的MQ集群具有局限性。
镜像集群
镜像集群,本质上是主从模式。与Redis主从集群不同的是,主从并不是创建时就决定了的,而是以队列为核心,创建队列的是该队列的主节点,其他节点为该队列的从节点。从节点会同步备份主节点的交换机、队列、队列中的消息。
当消费者绑定的是mq1节点中的one.queue1队列时,因为mq3同步备份了mq1的数据,所以通过访问mq3节点就能得到该队列中的消息,并且当(mq1)宕机时,其余的镜像节点(mq3)会代替成为主节点。
结构图
搭建
镜像集群搭建有3中配置模式,详细参考:rabbitMq集群之镜像模式,这里以exactly为例:
第一步:创建
在之前普通集群的情况下,敲下面的命令,表示镜像数量设置2,匹配队列名以“two”开头的队列;
docker exec -it mq1 rabbitmqctl set_policy ha-two "^two\." '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'
第二步:测试
打开mq1的管理平台,创建一个队列“two.queue”,看到可以指定节点,说明镜像集群已搭建成功;
点击队列特征(features)可以看到策略信息,one.queue8081没有,是因为不是以“two”开头的队列;
第三步:使用
在mq1节点下two.queue8081队列内添加一条消息;
在mq3节点下,可以看到消息已同步过来;
此时,把mq1宕机,看其他节点还能不能查看到消息;
可以看到,mq3仍能查看到mq1当时创建的队列内的消息,并且队列的Node信息已经更改为rabbit@mq2;
小结
镜像集群,本质上是主从模式,可以同步节点之间的交换机、队列、队列内的消息,并且当主节点宕机时,其余镜像节点会代替称为主节点。
仲裁队列
仲裁队列时RabbitMQ3.8之后增加的功能,效果与镜像队列一样,但省去了搭建镜像集群的操作,十分方便。
搭建
第一步:创建仲裁队列
可以看到Node信息里面有“+2”,表示该队列另有两个镜像节点。默认情况是5,节点数小于5以实际为准;
第二步:添加消息
在quorum.queue队列内添加消息;
第三步:让MQ1宕机
在mq2中可以看到quorum.queue队列的消息内容
手动让mq1宕机,在看看
可以看到,在mq2中还是能看到quorum.queue队列内的消息,并且Node节点已更改为rabbit@mq3,并且数量-1,仲裁队列达到了与镜像集群相同的效果。
代码中使用
如果需要在代码中创建仲裁队列,也十分方便,只需在配置文件中指定节点IP(注意此时端口号为程序的端口号,同样也需要开放这些端口号),连接集群:
spring:
rabbitmq:
addresses: 118.178.228.175:8071, 118.178.228.175:8072, 118.178.228.175:8073
username: root
password: 123456
virtual-host: /
创建Quorum队列
/**
* 创建仲裁队列
* @return
*/
@Bean
public Queue quorumQueue(){
return QueueBuilder.durable("quorum.queue")
.quorum()
.build();
}
小结
仲裁队列效果与镜像集群相同,省去了搭建镜像集群的操作,使用起来非常方便。另外,仲裁队列可集群扩容,增加集群的可用性(参考:http://t.csdn.cn/BwMeN)
总结
MQ集群分普通集群、镜像集群和仲裁队列三种,就可用性来说,普通集群局限性很大,只能做到“转发”,节点宕机了就没办法;镜像集群和仲裁队列效果相同,但仲裁队列不用额外敲命令,推荐使用。