nacos 默认采用临时节点ephemeral,满足CAP中 AP原则,各节点是pear to pear 模式,相互之间无感知,因此对于一个集群来说,只要leader存活,即使其他所有follower全部down了,也能正常对外提供服务,基于此,nacos是可能产生脑裂的。
正常情况,leader,follower相互之间都有通信,示意如下
当leader与follower之间网络异常(各节点均是up状态,且leader能对外提供服务,但无法与follower通信;各follower之间能正常通信),示意图如下:
此时因为leader是状态正常,且与应用之间通信是正常的,因此仍能正常对外提供服务;
follower无法与leader通信,因此会触发新的选举,投票满足过半数原则,因此能正常选举新的leader,且能正常对外提供服务;
重新选举后集群示意图,此时产生了2个leader,出现了脑裂
验证过程如下:
准备三台机器,启动nacos,集群状态如下
序号 | ip /别名 | port | role |
1 | 192.168.198.131(node1) | 8848 | LEADER |
2 | 192.168.198.132(node2) | 8848 | FOLLOWER |
3 | 192.168.198.133(node3) | 8848 | FOLLOWER |
1.正常状态
此时集群正常对外提供服务
step1:
1.1 leader 打开防火墙
systemctl status firewalld
systemctl start firewalld
1.2 leader 拒绝2个follower 访问8848端口
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.198.132" port protocol="tcp" port="8848" reject"
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.198.133" port protocol="tcp" port="8848" reject"
firewall-cmd --reload
firewall-cmd --zone=public --list-rich-rules
1.3 learder 打开8848端口,允许外部应用访问8848端口
firewall-cmd --zone=public --add-port=8848/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --list-ports
此时leader状态正常,且能对外提供服务(虽follwer已无法访问leader,但leader能正常访问follower,因此不会触发选举)集群示意图如下
2.1 follower-1 打开防火墙
systemctl status firewalld
systemctl start firewalld
2.2 follower-2 打开防火墙
systemctl status firewalld
systemctl start firewalld
2.3 follower-1/2 拒绝leader 连接访问
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.198.131" port protocol="tcp" port="8848" reject"
firewall-cmd --reload
firewall-cmd --zone=public --list-rich-rules
2.4 follower-1/2 打开8848端口
firewall-cmd --zone=public --add-port=8848/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --list-ports
至此 follower1/2与leader无通信,且leader与follower1/2之间也无通信,因此follower会触发选举并产生新的leader;原来的leader照旧;示意图如下:
follower1/2选举出新的leader
新选举的leader能正常对外提供服务;
此时再观察原leader node1,也能正常对外提供服务,验证了脑裂;
step3 验证新集群选举
3.1 停止新集群的2个节点
3.2 重新启动这2个节点
验证应用注册
step4 关闭防火墙验证2个leader
4.1 关闭follower机器防火墙
#关闭防火墙
systemctl stop firewalld
#清除防火墙配置
rm -rf /etc/firewalld/zones
此时 由于新/旧leader均能与这个follower通信,因此会出现如下2个集群的场景,示意图如下:
follower与原leader组成的集群
follower与新leader组成的集群
4.2 关闭原leader防火墙
#关闭防火墙
systemctl stop firewalld
#清除配置
rm -rf /etc/firewalld/zones
此时 登录follower节点 有2个leader,且该follower与2个leader均能正常对外提供服务;
leader1 注册的应用 会同步至follower 但leader2无法同步该应用注册信息;
leader2 注册的应用 会同步至follower 但leader1无法同步该应用注册信息;
4.3 关闭新leader防火墙
#关闭防火墙
systemctl stop firewalld
#清除配置
rm -rf /etc/firewalld/zones
此时集群重新回归正常状态,只会有一个leader
最后 清除各节点防火墙配置,恢复至原状态
rm -rf /etc/firewalld/zones
问题延申:
1. 依照此种场景,若nacos采用持久节点模式p(满足CP原则)会产生脑裂吗?
2.依照此种场景,zookeeper集群会产生脑裂吗?
答案是否定的,因为zk遵循的是CP原则,当集群中过半数节点不可用时,即使leader节点仍然存活,整个集群也是无法对外提供服务,leader此时会进入looking状态;另外2个follower节点会选举出新的leader;当原leader网络恢复正常时,会转为follower角色;