RabbitMQ 高可用集群搭建
前提条件:本文操作基于Linux Ubuntu系统
RabbitMQ 构建模式介绍
单一模式: 单机运行一个rabbitmq;
普通模式: 默认集群模式,以两个节点(rabbit01、rabbit02)为例进行说明。对于队列来说,消息实体只存在于其中一个节点rabbit01,rabbit01和rabbit02两个节点有相同的数据。当消息进入rabbit01节点的队列后,若消费者从2节点消费,则rabbitmq会临时在rabbit01、rabbit02间进行消息传输,把rabbit01中的消息实体取出并经过rabbit02发送给consumer。所以consumer应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理queue。否则无论consumer连rabbit01还是rabbit02,出口总在rabbit01,会产生瓶颈。当rabbit01节点故障后,rabbit02节点无法取到rabbit01节点中还未消费的消息实体。如果做了消息持久化,那么得等rabbit01 节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象
镜像模式(本文的方案): 基于普通模式集群,在策略里面添加镜像策略。把需要的队列做成镜像队列,属于HA方案。该模式解决了普通模式中的问题,根本区别在于消息实体会主动在镜像节点间同步,而不是在客户端拉取数据时临时拉取。当然弊端就是降低系统性能,大量消息写入,集群内的网路带宽会被大大消耗。
高可用集群搭建:基于RabbitMQ镜像模式
镜像模式高可用集群搭建
如果RabbitMQ集群是多个Broker节点组成的,那么从服务的整体可用性上来说,该集群对于单点故障时有弹性的,但是同时也需要注意:尽管交换机和绑定关系能够在单点故障问题上幸免于难,但是队列和其上的存储的消息却不行,这是因为队列进程及其内容仅仅维持在单个节点之上,所以一个节点的失效表现为其对应的队列不可用
引入镜像队列的机制,可以将队列镜像到集群中的其他Broker节点之上,如果集群中的一个节点失效了,队列能自动地切换到镜像中的另一个节点上以保证服务的可用性。在通常的用法中,针对每一个配置镜像的队列都包含一个主节点(master)和若干个从节点(slave),相应的结构可以参考下图:
slave会准确地按照master执行命令的顺序进行动作,故slave与master上维护的状态应该是相同的。如果master由于某种原因失效,那么“资历最老”的slave会被提升为新的master。根据slave加入的时间排序,时间最长的slave即为“资历最老”。发送到镜像队列的所有消息会被同时发往master和所有的slave上,如果此时master挂掉了,消息还会在slave上,这样slave提升为master的时候消息也不会丢失。除发送消息(Basic.Publish)外的所有动作都只会向master发送,然后再由master将命令执行的结果广播给各个slave
如果消费者与slave建立连接并进行订阅消费,其实质上都是从master上获取消息,只不过看似是从slave上消费而已。比如消费者与slave建立了TCP连接之后执行一个Basic.Get的操作,那么首先是由slave将Basic.Get请求发往master,再由master准备好数据返回给slave,最后由slave投递给消费者。这里的master和slave是针对队列而言的,而队列可以均匀地散落在集群的各个Broker节点中以达到负载均衡的目的,因为真正的负载还是针对实际的物理机器而言,而不是内存中驻留的队列进程
RabbitMQ的镜像队列同时支持publisher confirm和事务两种机制。在事务机制中,只有当前事务在全部镜像中执行之后,客户端才会收到Tx.Commit-Ok的消息。同样的,在publisher confirm机制中,生产者进行当前消息确认的前提是该消息被全部镜像所接收了
RabbitMq Linux环境安装
不同linux操作系统,命令可能存在差异。
以下只提供了apt-get的安装方式
安装前准备
请查看高可用环境基础配置文档
Docker部署单机集群
该场景一般仅用于测试,生产环境请使用多机集群部署来实现
在部署服务器上面创建以下docker-compose.yml:
version: '3'
services:
rabbit1:
image: harbor.hipermatrix.com:10300/edge/rabbitmq-cluster:3.8.6-management
hostname: rabbitmq1
container_name: rabbitmq1
environment:
- ERLANG_COOKIE=.erlang.cookie.cluster
ports:
- "5672:5672"
- "15672:15672"
networks:
- iot
rabbit2:
image: harbor.hipermatrix.com:10300/edge/rabbitmq-cluster:3.8.6-management
hostname: rabbitmq2
container_name: rabbitmq2
environment:
- ERLANG_COOKIE=.erlang.cookie.cluster
- CLUSTER_WITH=rabbitmq1
- ENABLE_RAM=true
- RABBITMQ_LOGS=/var/log/rabbitmq/server.log
ports:
- "5673:5672"
- "15673:15672"
networks:
- iot
rabbit3:
image: harbor.hipermatrix.com:10300/edge/rabbitmq-cluster:3.8.6-management
hostname: rabbitmq3
container_name: rabbitmq3
environment:
- ERLANG_COOKIE=.erlang.cookie.cluster
- CLUSTER_WITH=rabbitmq1
- ENABLE_RAM=true
- RABBITMQ_LOGS=/var/log/rabbitmq/server.log
ports:
- "5674:5672"
- "15674:15672"
networks:
- iot
networks:
iot:
external: true
如果docker的iot网络不存在,请使用 docker network create iot 创建出来
然后执行以下命令启动rabbitmq集群
docker-compose up -d
大约等待30秒左右,集群启动完毕
Docker部署多节点集群
实际生产环境中,都是部署多节点集群,假设已经准备了3个以下的节点:
节点1: 192.168.1.101
节点2: 192.168.1.102
节点3: 192.168.1.103
节点1上执行:
docker run -d --name rabbitmq1 --hostname rabbitmq1 --net iot \
--add-host rabbitmq2:192.168.1.102 --add-host rabbitmq3:192.168.1.103 \
-e ERLANG_COOKIE=.erlang.cookie.cluster \
-p 5672:5672 -p 15672:15672 -p 4369:4369 -p 25672:25672 -p 1883:1883 \
-p 6000-6010:6000-6010 -p 35672-35682:35672-35682 \
harbor.hipermatrix.com:10300/edge/rabbitmq-cluster:3.8.6-management
节点2上执行:
docker run -d --name rabbitmq2 --hostname rabbitmq2 --net iot \
--add-host rabbitmq1:192.168.1.101 --add-host rabbitmq3:192.168.1.103 \
-e ERLANG_COOKIE=.erlang.cookie.cluster -e CLUSTER_WITH=rabbitmq1 \
-e RABBITMQ_LOGS=/var/log/rabbitmq/server.log -e ENABLE_RAM=true\
-p 5672:5672 -p 15672:15672 -p 4369:4369 -p 25672:25672 -p 1883:1883 \
-p 6000-6010:6000-6010 -p 35672-35682:35672-35682 \
harbor.hipermatrix.com:10300/edge/rabbitmq-cluster:3.8.6-management
节点3上执行:
docker run -d --name rabbitmq3 --hostname rabbitmq3 --net iot \
--add-host rabbitmq1:192.168.1.101 --add-host rabbitmq2:192.168.1.102 \
-e ERLANG_COOKIE=.erlang.cookie.cluster -e CLUSTER_WITH=rabbitmq1 \
-e RABBITMQ_LOGS=/var/log/rabbitmq/server.log -e ENABLE_RAM=true\
-p 5672:5672 -p 15672:15672 -p 4369:4369 -p 25672:25672 -p 1883:1883 \
-p 6000-6010:6000-6010 -p 35672-35682:35672-35682 \
harbor.hipermatrix.com:10300/edge/rabbitmq-cluster:3.8.6-management
待3个节点的服务启动完成后,rabbitmq集群即搭建完成,访问任意一个节点的管理页面(如http://192.168.1.101:15672, 根据实际情况改变ip地址),在管理页面可以看到集群已经正常加入进来三个节点,如下图:
镜像模式高可用集群搭建(这里使用hanode3,hanode4来进行部署)
- 两台服务器搭建运行rabbitmq :
# 第一台服务器
apt-get install erlang-nox
apt-get install rabbitmq-server
rabbitmq-plugins enable rabbitmq_management
rabbitmq-plugins enable rabbitmq_web_stomp
# 第二台服务器
apt-get install erlang-nox
apt-get install rabbitmq-server
rabbitmq-plugins enable rabbitmq_web_stomp
rabbitmq-plugins enable rabbitmq_management
- 复制容器根目录下.erlang.cookie文件,应该是/var/lib/rabbitmq/.erlang.cookie,保证所有应用实例这个文件内容相同,可以复制,或者直接修改内容
scp /var/lib/rabbitmq/.erlang.cookie root@hanode4:/var/lib/rabbitmq/
- 重启第二个服务器并设置节点主从关系
第二台服务器加入集群
reboot
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@hanode3
rabbitmqctl start_app
- 主服务器添加管理员账号
rabbitmqctl add_user admin 123456
rabbitmqctl set_user_tags admin administrator
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
- 设置镜像模式
任意一个节点
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
查看状态:
rabbitmqctl cluster_status
- springboot项目使用方法
配置yml中设置如下
spring:
rabbitmq:
addresses: 192.168.13.52:5672,192.168.13.53:5672
username: admin
password: 123456
- 使用公司脚手架,注入RabbitTemplate实例就可以直接操作。代码无需改动,需要注意的是写入的高可用。消费的方式还是监听,消费本身没有高可用一说。写入的时候会重试几次,然后调用成功,切换节点的时候可能会造成数据丢失。业务逻辑要考虑完整。
- 经过测试,发现这种方案并不能完全保证在服务突然下线导致的数据丢失问题。所以业务设计的时候要考虑突发情况数据丢失的可能性,并且如果业务不下线,使用的是某一个实例,所以有性能瓶颈问题。如果需要负载均衡,需要另外的实施手段,这里不做说明。