RabbitMQ集群原理
多个RabbitMQ单节点,经过配置组成RabbitMQ集群;
集群节点之间共享元数据,比如有节点1,节点2,节点3,3个节点是普通集群,它们仅有相同的元数据,即交换机,队列的结构,不共享队列数据(默认);
RabbitMQ节点数据相互转发,客户端通过单一节点可以访问所有数据;
消息只存在其中的一个节点里面,假如消息A存储在节点1,消费者连接节点1消费消息时,可以直接取出来,但如果消费者连接的是其他节点,那RabbitMQ会把队列中的消息从存储它的节点中取出,并经过连接节点转发后再发送给消费者;
集群拓扑图
普通集群搭建步骤
设置主机名或host,使得节点之间可以通过名称访问;
安装RabbitMQ单节点;
复制Erlang cookie;集群需要保证各个节点有相同的token令牌,Erlang Cookie 值必须相同,也就是一个集群内 RABBITMQ_ERLANG_COOKIE 参数的值必须相同, 相当于不同节点之间通讯的密钥,erlang.cookie是erlang的分布式token文件,集群内各个节点的erlang.cookie需要相同,才可以互相通信;
启动RabbitMQ并组成集群;
docker-compose.yml如下
version: "3" services: rabbit1: image: rabbitmq:3.8.12-management-alpine hostname: rabbit_node1 ports: - 6672:5672 #集群内部访问的端口 - 25672:15672 #外部访问的端口 environment: - RABBITMQ_DEFAULT_USER=admin #用户名 - RABBITMQ_DEFAULT_PASS=dev #密码 - RABBITMQ_ERLANG_COOKIE=‘rabbitmq_cookie‘ privileged: true rabbit2: image: rabbitmq:3.8.12-management-alpine hostname: rabbit_node2 ports: - 6673:5672 - 25673:15672 #外部访问的端口 environment: - RABBITMQ_ERLANG_COOKIE=‘rabbitmq_cookie‘ links: - rabbit1 privileged: true rabbit3: image: rabbitmq:3.8.12-management-alpine hostname: rabbit_node3 ports: - 6674:5672 - 25674:15672 #外部访问的端口 environment: - RABBITMQ_ERLANG_COOKIE=‘rabbitmq_cookie‘ links: - rabbit1 - rabbit2 privileged: true
privileged:true 使用该参数,container内的root拥有真正的root权限,否则容器出现permission denied;
hostname自定义Docker容器的 hostname;
节点2
# 进入2号节点 docker exec -it compose_rabbit2_1 bash # 停止2号节点的rabbitmq rabbitmqctl stop_app # 配置2号节点,加入集群,--ram是以内存方式加入,忽略该参数默认为磁盘节点,rabbit@后面接hostname rabbitmqctl join_cluster rabbit@rabbit_node1 # 启动2号节点的rabbitmq rabbitmqctl start_app # 退出 exit
节点3
# 进入3号节点 docker exec -it compose_rabbit3_1 bash # 停止3号节点的rabbitmq rabbitmqctl stop_app # 配置3号节点,加入集群,--ram是以内存方式加入,忽略该参数默认为磁盘节点,rabbit@后面接hostname rabbitmqctl join_cluster rabbit@rabbit_node1 # 启动3号节点的rabbitmq rabbitmqctl start_app # 退出 exit
参考:[https://www.rabbitmq.com/rabbitmqctl.8.html#join_cluster]
参考:[https://www.rabbitmq.com/configure.html]
访问节点一的web管控台,可以看到多个节点
在节点1创建队列(持久化的),发送消息,测试节点2,节点3是否创建队列,接收到消息;
节点2通过节点自身的web管控台可以看到队列和消息
节点3通过节点自身的web管控台可以看到队列和消息
测试如果把节点1停止,节点2和节点3是否会收不到消息
节点2通过节点自身的web管控台可以看到节点1停止,该队列状态显示down;
节点3通过节点自身的web管控台可以看到节点1停止,该队列状态显示down;
节点1重新启动
节点2,节点3该队列的状态恢复;
如果磁盘节点挂掉后,如果没开启持久化数据就丢失了,其他节点也无法获取消息;
集群镜像队列原理
多个RabbitMQ单节点,经过配置组成RabbitMQ集群;
集群节点之间共享元数据,且共享队列数据;
RabbitMQ节点数据互相转发,客户端通过单一节点可以访问所有数据;
集群+镜像队列拓扑图
rabbitmq的策略policy是用来控制和修改集群的vhost队列和Exchange复制行为,即设置哪些Exchange或者queue的数据需要复制、同步,以及如何复制同步;
创建一个策略来匹配队列
-
路径:rabbitmq管理页面 —> Admin —> Policies —> Add / update a policy
-
参数: 策略会同步同一个VirtualHost中的交换器和队列数据
- name:自定义策略名称
- Pattern:^ 匹配符,代表匹配所有
- Definition:ha-mode=all 为匹配类型,分为3种模式:all(表示所有的queue)
ha-mode: 指明镜像队列的模式,可选下面的其中一个 all:表示在集群中所有的节点上进行镜像同步(一般都用这个参数) exactly:表示在指定个数的节点上进行镜像同步,节点的个数由ha-params指定 nodes:表示在指定的节点上进行镜像同步,节点名称通过ha-params指定 ha-sync-mode:镜像消息同步方式 automatic(自动),manually(手动)
也可以使用命令操作:
rabbitmqctl set_policy
配置好后,+2的意思是有三个节点,一个节点本身和两个镜像节点, 且可以看到策略名称;
集群重启的顺序是固定的,并且是相反的,最后关闭必须是磁盘节点,否则容易造成集群启动失败、数据丢失等异常情况;
集群+镜像队列只是实现了数据冗余和可扩展,并没有做到高可用;
实现高可用方式:
客户端负载均衡,直接在SpringBoot配置中设置多个地址,如下:
spring.rabbitmq.addresses=127.0.0.1,127.0.0.2,127.0.0.3
服务端负载均衡
配置HAProxy+Keepalived;
HAProxy一款高可用,负载均衡以及基于TCP和HTTP应用的代理软件,可以代理4层和7层,适合负载较大的web站点,可以支持数以万计的并发连接;
Keepalived用于做热备,主要来防止服务器单点故障的发生(如HAProxy宕机,使用Virtual IP解决),以VRRP协议为实现;