9
10
本文总结《RabbitMQ实战指南》网络分区章节,并亲自实践才有这篇文章,手动处理章节详细记录了操作过程中的注意事项.如果你没有经历过网络分区,就不算真正掌握RabbitMQ~
1
网络分区(脑裂)
网络分区对于RabbitMQ本身而言有利有弊,在遇到网络分区时不必过于惊慌. 许多情况下,网络分区都是由单个节点的网络故障引起的,而且通常会形成一个大分区和一个单节点的分区,如果之前又配置了镜像,那么可以在不影响服务可用性、不丢失消息的情况下从网络分区的情形下恢复.
当一个集群发生分区时,这个集群会分成两个部分或者更多,他们各自为政.互相都认为对方分区内的节点已经挂了,包括队列、交换器及绑定等元数据的穿件和销毁都处于自身分区内,与其他分区无关.如果原集群中配置了镜像队列,而这个镜像队列又牵涉两个或者更多个网络分区中的节点时,每一个网络分区中都会出现一个master节点,对于各个网络分区,次队列都是相互独立.当然也会又一些其他未知的、怪异的事情发生.当网络恢复时,网络分区的状态还是会保持,除非你采取了一些措施去解决它.
2
网络分区的判定
RabbitMQ集群节点内部通信端口默认为:25672,两两节点之间都会有信息交互.如果某节点出现网络故障,或者端口不通,则会致使与此节点的交互出现中断,这里就会有个超时判断机制,继而判定网络分区,下面段落详细介绍了分区的判断.
对于网络分区的判定是与net_ticktime这个参数息息相关的,此参数默认值为:60秒.注意与heartbeat_time的区别,heart_time是指客户端与RabbitMQ服务之间通信的心跳时间,针对5672端口而言.如果发生超时则会有net_tick_timeout的信息报出.在RabbitMQ集群内部的每个节点之间会每隔四分之一的net_ticktime记一次应答(tick).如果有任何数据被写入节点中,则此节点被认为已经被应答(ticked)了,如果连续4次,某个节点没有被应答(ticked),则可以判定次节点已经处于:“down”状态,其余节点可以将次节点剥离出当前分区.
将连续4次的tick时间记为T,那么T的取值范围为:
0.75 * net_ticktime < T < 1.25 * net_ticktime
如图可以形象地描绘出这个取值范围的缘由:

=ERROR REPORT==== 9-Aug-2020::20:15:45 ===
Mnesia('rabbit@rmq-node2'): ** ERROR ** mnesia_event got {inconsistent_database, starting_partitioned_network, 'rabbit@rmq-node1'}
除了通过查看RabbitMQ服务日志的方式,还有以下3种方法可以查看是否出现了网络分区
3
网络分区查看
1、通过rabbitmqctl工具查看即采用rabbitmqctl cluster_status命令.未发生分区的情况,如下图:[root@rmq-node3 ~]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@rmq-node3'
[{nodes,[{disc,['rabbit@rmq-node2','rabbit@rmq-node1']},
{ram,['rabbit@rmq-node3']}]},
{running_nodes,['rabbit@rmq-node1','rabbit@rmq-node2','rabbit@rmq-node3']},
{cluster_name,<<"rabbit@rmq-node1">>},
{partitions,[]}, #注意,这里为空数组,表明没有发生网络分区
{alarms,[{'rabbit@rmq-node1',[]},
{'rabbit@rmq-node2',[]},
{'rabbit@rmq-node3',[]}]}]
发生分区的情况:
[root@rmq-node3 ~]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@rmq-node3'
[{nodes,[{disc,['rabbit@rmq-node2','rabbit@rmq-node1']},
{ram,['rabbit@rmq-node3']}]},
{running_nodes,['rabbit@rmq-node1','rabbit@rmq-node2','rabbit@rmq-node3']},
{cluster_name,<<"rabbit@rmq-node1">>},
{partitions,[{'rabbit@rmq-node1',['rabbit@rmq-node2','rabbit@rmq-node3']}]}, #这里是发生了network partitions
{alarms,[{'rabbit@rmq-node1',[]},
{'rabbit@rmq-node2',[]},
{'rabbit@rmq-node3',[]}]}]
2、通过RabbitMQ管理控制台查看


4
网络分区之手动处理
a、步骤1挂起生产者或者消费者进程. 这样可以减少消息不必要的丢失,如果进程数过多,情形又比较紧急,也可以跳过次步骤.
b、步骤2删除镜像队列的配置. 使用命令:rabbitmqctl clear_policy [-p vhost] {policy_name} , 命令删除示例(也可以在web管理台删除):rabbitmqctl clear_policy -p /xmm ha-all
为什么要做这一步?: 因为不做这一步会队列发生漂移,所有的master会漂移到同一个节点上.还要注意:1.每个分区都要删除,如果只删除一个分区,是不行的2.查看policy的命令为:rabbitmqctl list_policies [-p ] eg:rabbitmqctl list_policies -p /xmm
c、步骤3挑选信任分区. 挑选的优先级如下:
d、步骤4关闭所有非信任区节点. 采用rabbitmqctl stop_app命令关闭注意:关闭所有的非信任分区的节点,就是全部关闭; 绝对不能关闭一个重启一个,这样不但解决不来问题,还会出现新的分区e、步骤5启动非信任分区中的节点.采用rabbitmqctl start_app命令启动f、步骤6检查网络分区是否恢复,如果已经恢复则转步骤8;如果还有网络分区的报警则转步骤7注意:检查方法,可以参考:3、网络分区查看g、步骤7重启信任分区中的节点.可以挨个重启h、步骤8重新添加镜像队列的配置,可以使用如下命令(也可以使用管理控制台):
rabbitmqctl set_policy [-p vhost] [--priority priority] [--apply-to apply-to] {name} {pattern} {definition}
# {name} 表示策略名称;# {pattern} 表示当匹配到给定资源的正则表达式,使该策略得以应用; # {definition} 表示策略的定义,作为一个JSON项,在多数shell中,你很可能需要去应用它# {priority} 表示策略的优先级的整数,数据越大表示优先级越高,默认值为0# {apply_to} 表示策略应该应用的类型:queues/exchange/all,默认值是 all也可以指定模式,举例如下:
rabbitmqctl set_policy -p /liuss --apply-to all liuss-all-policy "^" '{"ha-mode":"nodes","ha-params":["rabbit@vm-10-112-30-103","rabbit@vm-10-112-30-101","rabbit@vm-10-112-30-102"]}'
rabbitmqctl set_policy -p /zhou --apply-to all zhou-all-policy "^" '{"ha-mode":"nodes","ha-params":["rabbit@vm-10-112-30-102","rabbit@vm-10-112-30-103","rabbit@vm-10-112-30-101"]}'
rabbitmqctl set_policy -p /xmm --apply-to all xmm-all-policy "^" '{"ha-mode":"nodes","ha-params":["rabbit@vm-10-112-30-101","rabbit@vm-10-112-30-102","rabbit@vm-10-112-30-103"]}'
i、步骤9
恢复生产者和消费者进程
5
网络分区自动处理自动处理大概意思就是通过配置一些参数,RabbitMQ根据预设的参数进行处理,但是个人还是建议手动处理,可控,这里只是说一下三种方式,详细的解释可读:《RabbitMQ实战指南》或者官网查看.
1、ignore模式发生网络分区时,不做任何动作,需要人工介入;
人工介入就按:5、网络分区之手动处理 处理
rabbitmq.config中增加如下配置,默认不加就是这种模式


