1. 概述
正常情况下,很难观察到RabbitMQ网络分区的发生。为了更好的理解网络分区,需要某些手段将其模拟出来,以便对其做相应的分析处理,进而在正式应用环境中遇到类似情形可以处理的游刃有余。往长远方面讲,也可以采取一些必要的手段去避免网络分区的发生,或者可以监控网络分区以便对其迅速处理。
模拟网络分区的方式有多种,主要分为以下3大类:
- iptables封禁/解封IP地址或者端口号。
- 关闭/开启网卡。
- 挂起/恢复操作系统。
下面对这3大类做详细分析。
2. iptables的方式
由于RabbitMQ集群内部节点通信端口默认为25672,可以封禁这个端口来模拟出net_tick_timeout,然后再开启此端口让集群判断出网络分区的发生。举例说明,整个RabbitMQ集群由3个节点组成,分别为node1, node2, node3。此时我们要模拟node2节点被剥离出当前分区的情形,即模拟[node1, node3]和[node2]两个分区。可以在node2上执行如下命令以封禁25672端口。如果在配置中修改过这个端口号,可以将下面的命令改成相应的端口号即可。
iptables -A INPUT -p tcp --dport 25672 -j DROP
iptables -A OUTPUT -p tcp --dport 25672 -j DROP
同时需要监测各个节点的服务日志,当有如下相似信息出现时即为已经判定出net_tick_timeout:
=INFO REPORT==== 10-Oct-2017::11:53:03 ===
rabbit on node rabbit@node2 down
=INFO REPORT==== 10-Oct-2017::11:53:03 ===
node rabbit@node2 down: net_tick_timeout
当然,如果不想去监测各个节点的服务日志,也可以等待75秒以确保出现net_tick_timeout。注意此时只判定出net_tick_timeout,要等node2网络恢复之后,即解封25672端口之后才会判定出现网络分区。解封命令如下:
iptables -D INPUT 1
iptables -D OUTPUT 1
至此,node2节点与其他节点的内部通信已经恢复,如果此时查看集群的状态可以发现[node1, node3]和[node2]已形成两个独立的分区。
还可以使用iptables封禁IP地址的方法模拟网络分区。假设整个RabbitMQ集群的节点名称与其IP地址对应如下:
node1 192.168.0.2
node2 192.168.0.3
node3 192.168.0.4
如果要模拟出[node1, node3]和[node2]两个分区的情形,可以在node2节点上执行:
iptables -I INPUT -s 192.168.0.2 -j DROP
iptables -I INPUT -s 192.168.0.4-j DROP
对应的解封命令为:
iptables -D INPUT 1
iptables -D INPUT 1
或者也可以分别在node1, node3节点上执行:
iptables -I INPUT -s 192.168.0.3 -j DROP
与其对应的解封命令为:
iptables -D INPUT 1
如果集群的节点部署有跨网络分段的话,可以采取禁用整个网络段的方式模拟网络分区。假设RabbitMQ集群中3个节点和其对应的IP关系如下:
node1 192.168.0.2
node2 192.168.1.3
node3 192.168.0.4
如果要模拟出[node1, node3]和[node2]两个分区的情形,可以在node2节点上执行:
iptables -I INPUT -s 192.168.0.0/24 -j DROP
对应的解封命令也是:iptables -D INPUT 1。
3. 封禁/解封网卡的方式
操作网卡的方式和iptables的方式有相似之处,都是模拟网络故障来产生网络分区。首先需要使用ifconfig命令来查询出当前的网卡编号,如下所示,一般情况下单台机器只有一个网卡。(这里暂时不考虑多网卡的情形,因为对于RabbitMQ来说,多网卡的情况造成的网络分区异常复杂。)
[root@node1 rabbit@node1]# ifconfig
eth0 Link encap:Ethernet HWaddr FA:16:3E:A8:FF:31
inet addr:192.168.1.2 Bcast:192.168.1.255 Mask:255.255.224.0
inet6 addr: fe80::f816:3eff:fea8:ff31/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1
RX packets:547632449 errors:0 dropped:0 overruns:0 frame:0
TX packets:5745162 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:82813557343 (77.1 GiB) TX bytes:3099664440 (2.8 GiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:111152 errors:0 dropped:0 overruns:0 frame:0
TX packets:111152 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:5401343 (5.1 MiB) TX bytes:5401343 (5.1 MiB)
假设在node1, node2, node3三个节点的RabbitMQ集群中,node2的网卡编号为eth0,此时要模拟网络分区[node1, node3]和[node2]的情形,需要在node2上执行以下命令关闭网卡:
ifdown eth0
待判定出net_tick_timeout之后,再开启网卡:
ifup eth0
这样就可以模拟出网络分区的情形。当然也可以使用service network stop和service network start两个命令来模拟网络分区,原理同ifdown/ifup eth0的方式。
4. 挂起/恢复操作系统的方式
除了模拟网络故障的方式,操作系统的挂起和恢复操作也会导致集群内节点的网络分区。因为发生挂起的节点不会认为自身已经失败或者停止工作,但是集群内的其他节点会这么认为。如果集群中的一个节点运行在一台笔记本上,然后你合上了笔记本,那么这个节点就挂起了。或者一个更常见的现象,集群中的一个节点运行在某台虚拟机上,然后虚拟机的管理程序挂起了这个虚拟机节点,这样节点就被挂起了。待(0.75*net_ticktime, 1.25*net_ticktime)时间之后,判断出net_tick_timeout,再恢复挂起的节点即可以模拟出网络分区的情形。