暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

RabbitMQ之脑裂

不修边幅的创客 2020-09-10
847
点击上方蓝色字体,选择“设为星标”

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

如图可以形象地描绘出这个取值范围的缘由:


如图中每个节点代表一次tick判定的时间戳,在2个临界值0.75 * net_ticktime 和1.25 * net_ticktime之间可以连续执行4次的tick判定.默认情况下,在45s < T <75s之间会判定出net_tick_timeout.
RabbitMQ不仅会将队列、交换器及绑定等信息存储在Mnesia数据库中,而且许多围绕网络分区的一些细节也都和这个Mnesia的行为相关.如果一个节点不能在T时间连上另一个节点,那么Mesia通常认为这个节点已经挂了,就算之后两个节点又恢复了内部通信,但是这两个节点都会认为对方已经挂了,Mnesia此时认定了网络分区的情况.这些会被记录到RabbitMQ的服务日志之中,如下:
=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管理控制台查看
3、通过HTTP API口调用节点信息查看
见到红色方框信息则表示发生了分区


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 <vhost>]       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中增加如下配置,默认不加就是这种模式


2、pause-minority模式
对于对等分区的处理不够优雅(比如每个分区的节点一样多),可能会关闭所有的节点. 一般情况下,可应用于非跨机架、奇数节点数的集群中;
3、pause-if-all-down模式
对于受信节点的选择尤为考究,尤其是在集群中所有节点硬件配置相同的情况下.此处模式可以处理对等分区的情形
文章转载自不修边幅的创客,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论