标签:ini 无法 内容 params 离线 没有 增加 数据 配置
1. 创建镜像队列模式
注意,到此步骤,我们假设是你已经创建好了RabbitMQ集群。
1.1 增加镜像队列的Policy
打开你的RabbitMQ管理首页,在Admin->Policy链接下开始创建Policy:
- Name: 你配置的Policy名称;
- Pattern: 匹配模式,图片的是匹配testMirror开头的交换机和队列;
- Priority: 优先级;
- Definition: 一些模式的定义,RabbitMQ已经列出了以下常见的模式定义。ha-mode是指定镜像队列的模式,有效值为all/exactly/nodes。其中all表示在集群中所有的节点上进行镜像;exactly表示在指定个数的节点上进行镜像,节点的个数由ha-params指定;nodes表示在指定的节点上进行镜像,节点名称通过ha-params指定。ha-sync-mode为指定镜像队列中消息的同步方式,有效值为automatic(自动同步),manually(手动同步);默认是manually,请注意一定要记得设置为automatic(自动同步),否则消息在镜像队列中是不会自动同步的(即普通集群模式),即新节点加入时不会自动同步消息和元数据,只能通过命令手动去同步。
1.2 代码声明交换机、队列、绑定等
1.3 查看镜像队列是否声明成功
查看你刚声明的队列的详情:
可以看到,ha-mode、node、salve等属性都已经创建成功。
2. 镜像队列说明
2.1 关于node节点
queue有master节点和slave节点。 要强调的是,在RabbitMQ中master和slave是针对一个queue而言的,而不是一个node作为所有queue的master,其它node作为slave。一个queue第一次创建的node为它的master节点,其它node为slave节点。
2.2 镜像队列服务提供方式
如上图所示,在镜像队列集群模式中,对某个queue来说,只有master对外提供服务,而其他slave只提供备份服务,在master所在节点不可用时,选出一个slave作为新的master继续对外提供服务。
无论客户端的请求打到master还是slave最终数据都是从master节点获取。当请求打到master节点时,master节点直接将消息返回给client,同时master节点会通过GM(Guaranteed Multicast)协议将queue的最新状态广播到slave节点。GM保证了广播消息的原子性,即要么都更新要么都不更新。
当请求打到slave节点时,slave节点需要将请求先重定向到master节点,master节点将将消息返回给client,同时master节点会通过GM协议将queue的最新状态广播到slave节点。
所以,多个客户端连接不同的镜像队列不会产生同一message被多次接受的情况。
2.3 RabbitMQ集群处理新增节点
如果有新节点加入,RabbitMQ不会同步之前的历史数据,新节点只会复制该节点加入到集群之后新增的消息。
既然master节点退出集群会选一个slave作为master,那么如果不幸选中了一个刚刚加入集群的节点怎么办?那消息不就丢了吗?这里您可以把心放到肚子里,RabbitMQ集群内部会维护节点的状态是否已经同步,使用rabbitmqctl的synchronised_slave_pids参数,就可以查看状态。如果slave_pids和synchronised_slave_pids里面的节点是一致的,那说明全都同步了;如果不一致很容易比较出来哪些还没有同步,集群只会在“最老”的slave节点之间选一个出来作为新的master节点。另外对于node节点的重启也是按照新节点来处理的。
2.4 镜像队列注意点
- 镜像队列不能作为负载均衡使用,因为每个声明和消息操作都要在所有节点复制一遍。
- ha-mode参数和durable declare对exclusive队列都不生效,因为exclusive队列是连接独占的,当连接断开,队列自动删除。所以实际上这两个参数对exclusive队列没有意义。
- 每当一个节点加入或者重新加入(例如从网络分区中恢复回来)镜像队列,之前保存的队列内容会被清空。
- 对于镜像队列,客户端basic.publish操作会同步到所有节点;而其他操作则是通过master中转,再由master将操作作用于salve。比如一个basic.get操作,假如客户端与slave建立了TCP连接,首先是slave将basic.get请求发送至master,由master备好数据,返回至slave,投递给消费者。
2.5 镜像队列的故障恢复
假设两个节点(A和B)组成一个镜像队列。
- 场景1:A先停,B后停。 该场景下B是master(disk节点,A是ram),只要先启动B,再启动A即可。或者先启动A,再在30秒之内启动B即可恢复镜像队列。
- 场景2: A, B同时停。 该场景可能是由掉电等原因造成,只需在30秒之内连续启动A和B即可恢复镜像队列。
- 场景3:A先停,B后停,且A无法恢复。 该场景是场景1的加强版,因为B是master,所以等B起来后,在B节点上调用rabbitmqctl forget_cluster_node A,解除与A的cluster关系,再将新的slave节点加入B即可重新恢复镜像队列。
- 场景4:A先停,B后停,且B无法恢复。 该场景是场景3的加强版,比较难处理,早在3.1.x时代之前貌似都没什么好的解决方法,但是现在已经有解决方法了,在3.4.2版本亲测有效(我们当前使用的是3.3.5)。因为B是master,所以直接启动A是不行的,当A无法启动时,也就没办法在A节点上调用rabbitmqctl forget_cluster_node B了。新版本中,forget_cluster_node支持–offline参数,offline参数允许rabbitmqctl在离线节点上执行forget_cluster_node命令,迫使RabbitMQ在未启动的slave节点中选择一个作为master。当在A节点执行rabbitmqctl forget_cluster_node –offline B时,RabbitMQ会mock一个节点代表A,执行forget_cluster_node命令将B剔出cluster,然后A就能正常启动了。最后将新的slave节点加入A即可重新恢复镜像队列。
- 场景5: A先停,B后停,且A、B均无法恢复,但是能得到A或B的磁盘文件。 该场景是场景4的加强版,更加难处理。将A或B的数据库文件(默认在$RABBIT_HOME/var/lib目录中)拷贝至新节点C的目录下,再将C的hostname改成A或B的hostname。如果拷过来的是A节点磁盘文件,按场景4处理方式;如果拷过来的是B节点磁盘文件,按场景3处理方式。最后将新的slave节点加入C即可重新恢复镜像队列。
- 场景6:A先停,B后停,且A、B均无法恢复,且无法得到A或B的磁盘文件。 洗洗睡吧,该场景下已无法恢复A、B队列中的内容了。
以上内容就是RabbitMQ镜像队列原理分析的全部内容了,谢谢你阅读到了这里!
RabbitMQ镜像队列原理分析
标签:ini 无法 内容 params 离线 没有 增加 数据 配置
原文地址:https://www.cnblogs.com/youngdeng/p/14445002.html