一、踩坑背景:一次线上服务雪崩的根源

上周三凌晨两点,我正在刷剧,手机突然炸了——运维群里的告警一条接一条:订单服务连不上配置中心、支付接口超时、用户登录页直接报502。我手忙脚乱爬起来连公司VPN,第一反应是“配置中心挂了?”,赶紧登Nacos控制台,结果发现集群三个节点,两个显示“未同步”,一个显示“只读”。后来查日志才知道,前一天运维为了适配新的注册服务要求,把Nacos集群的运行模式从默认的AP改成了CP,结果中间某台节点的网络断了1分钟,直接触发了脑裂,核心配置丢了一大半。

可能有人会问,AP和CP到底是啥?为啥改个模式就出大事?别急,先给大家说清楚这俩模式的本质,用大白话讲:AP模式是“先保证服务能用,数据晚点同步也没事”,比如你刷抖音刷到一半,某个节点挂了,你不会卡,只是可能晚几秒刷到新视频;CP模式是“先保证数据准,服务能用不重要”,比如银行转账,必须等所有节点都确认转账成功才会给你反馈,哪怕中间节点挂了,服务会暂时停,也不能出现转了钱没记录的情况。

Nacos默认是AP模式,因为大部分场景是服务注册发现,服务能用比数据准更重要;但如果是配置中心这种需要强一致性的场景,很多人会改成CP。但改模式不是随便改的,我这次踩的坑,就是没搞清楚改模式的前置条件,以及脑裂的触发逻辑。

二、踩坑过程:从改模式到脑裂的完整链路

2.1 改模式的错误操作

先给大家看我当时改模式的操作,纯新手级别的错误,给大家避坑:

# 错误操作:直接修改单个节点的配置,没同步集群所有节点
# 1. 登Nacos节点1的服务器
ssh root@192.168.1.10
# 2. 找到配置文件,修改mode为CP
vi /home/nacos/conf/application.properties
# 修改内容:nacos.cluster.mode=cp
# 3. 重启节点1
sh /home/nacos/bin/shutdown.sh
sh /home/nacos/bin/startup.sh -m standalone
# 4. 没改节点2、节点3的配置,也没重启整个集群

大家看出来问题了吗?首先,改集群模式必须所有节点的配置一致,不然节点之间通信时,模式不兼容,直接会出问题;其次,改完模式后必须重启整个集群,不能只改一个节点;最后,启动参数里的-m standalone是单节点模式,和集群模式冲突,我当时脑子乱了,直接写错了。

2.2 脑裂的触发与数据丢失

改完模式后的第二天,节点1的服务器因为硬件问题,网络断了1分钟。这时候集群里的节点2、3发现节点1失联了,就会触发“选主”——CP模式下,集群必须有超过一半的节点同意,才能选出主节点,不然集群会进入“只读”状态,不接受任何新的写入操作。

当时的情况是:节点1失联,剩下节点2、3,两个节点,总节点数是3,超过一半需要2个以上(也就是3个都在线才能满足),所以选主失败,集群进入只读。但节点1网络恢复后,因为它的配置是CP,其他节点的配置还是默认的AP,模式不兼容,节点1不认可节点2、3的集群状态,自己形成了一个“伪集群”。

这时候就出现了脑裂:两个独立的集群都在运行,都能处理部分请求。节点1的集群里存了一部分配置,节点2、3的集群里存了另一部分配置,中间没有同步。等网络完全恢复后,集群尝试合并数据,结果因为配置冲突,核心的订单服务配置、支付服务配置直接被覆盖丢了,导致所有依赖Nacos的服务都连不上。

给大家看当时Nacos的日志片段,能看到模式不兼容的错误:

# 节点1的日志
2024-05-22 02:15:30 ERROR cluster.ClientConnection : Connection refused from 192.168.1.11, mode not match: local mode is CP, remote mode is AP
# 节点2的日志
2024-05-22 02:15:31 ERROR cluster.ClusterManager : Can not elect leader, available nodes size is 2, required size is 2 (total nodes 3, quorum is 2)

三、修复过程:从脑裂到恢复的实操步骤

当时我花了3个小时才把数据找回来,现在把修复步骤整理出来,遇到类似问题可以直接用:

3.1 步骤1:停止所有Nacos节点,隔离集群

首先要把整个集群停下来,防止脑裂继续扩散,也防止新的配置写入导致数据更乱:

# 分别在三个节点上执行停止命令
sh /home/nacos/bin/shutdown.sh
# 检查节点是否完全停止,确保没有Nacos进程
ps -ef | grep nacos | grep -v grep

3.2 步骤2:备份所有节点的配置数据

这一步非常重要,万一修复失败,还能回滚。Nacos的配置数据默认存在/home/nacos/data/目录下,包括config(配置数据)、naming(服务注册数据)、raft(Raft协议的日志,CP模式下用的):

# 在每个节点上执行备份命令,把data目录打包
tar -zcf /home/nacos/nacos_data_backup_$(date +%Y%m%d_%H%M%S).tar.gz /home/nacos/data/

3.3 步骤3:统一所有节点的模式配置,修正启动参数

我当时选择先把模式改回默认的AP,因为修复阶段要先保证服务能用,后续再评估是否需要改CP:

# 在每个节点上修改配置文件
vi /home/nacos/conf/application.properties
# 修改内容:nacos.cluster.mode=ap(默认值,也可以直接删掉这一行,默认就是AP)
# 同时修正启动参数,集群模式不能加-m standalone,正确的启动参数是:
sh /home/nacos/bin/startup.sh

3.4 步骤4:手动合并配置数据,解决冲突

因为之前两个脑裂集群的配置不统一,所以需要手动合并。Nacos的配置数据存在MySQL里(如果用的是内置数据库,需要从每个节点的data目录里导出),我当时用的是MySQL,所以直接连数据库,查config_info表,把两个节点的配置合并:

-- 连Nacos的配置数据库,查所有配置
SELECT * FROM config_info;
-- 发现冲突的配置,比如订单服务的配置,节点1的id是1001,节点2的id是1002,内容不同
-- 手动对比两个配置的内容,保留最新的有效配置
UPDATE config_info SET content='正确的订单配置内容' WHERE id=1001;
-- 删除重复的冲突配置
DELETE FROM config_info WHERE id=1002;

3.5 步骤5:启动集群,验证数据一致性

先启动一个节点,再启动另外两个,等集群稳定后,检查配置是否都同步了:

# 先启动节点1
sh /home/nacos/bin/startup.sh
# 启动节点2
sh /home/nacos/bin/startup.sh
# 启动节点3
sh /home/nacos/bin/startup.sh
# 检查集群状态,三个节点都显示“已同步”才正常
curl http://192.168.1.10:8848/nacos/v1/cluster/nodes

最后登Nacos控制台,检查所有服务的配置是否正常,再让各个服务重启,验证服务是否能正常连接。

四、核心知识点解析:AP、CP模式的适用场景与坑点

4.1 AP模式的特点与适用场景

AP模式的核心是“可用性优先”,用的是最终一致性,也就是说,数据会在所有节点上慢慢同步,不会因为某个节点的问题导致整个集群不可用。

  • 优点:集群可用性高,哪怕一半节点挂了,剩下的节点还能正常提供服务;适合大部分场景,比如服务注册发现、非核心配置。
  • 缺点:数据可能会出现暂时不一致,比如两个节点上的配置可能不一样,但最终会同步;不适合需要强一致性的场景,比如支付配置、核心业务配置。

4.2 CP模式的特点与适用场景

CP模式的核心是“一致性优先”,用的是强一致性,也就是说,所有节点上的数据必须完全一致,才能对外提供服务。

  • 优点:数据绝对一致,不会出现配置冲突;适合需要强一致性的场景,比如银行转账配置、核心业务的敏感配置。
  • 缺点:集群可用性低,必须有超过一半的节点在线,才能提供服务;如果节点数是偶数,比如4个节点,超过一半需要3个,那只要有2个节点挂了,整个集群就不可用了;改模式的要求非常高,必须所有节点配置一致,重启整个集群。

4.3 模式切换的坑点总结

  1. 配置必须一致:所有节点的模式配置必须完全一样,不然节点之间会出现模式不兼容的错误;
  2. 必须重启整个集群:改完模式后,不能只重启一个节点,必须所有节点都重启,保证模式生效;
  3. 节点数要求:如果改成CP模式,节点数必须是奇数,比如3个、5个、7个,这样才能保证超过一半的节点在线,集群能正常选主;
  4. 数据备份:切换模式前必须备份所有数据,防止切换过程中出现数据丢失;
  5. 测试环境验证:切换模式前,必须在测试环境验证,确保模式切换不会影响服务。

五、预防方案:避免脑裂与数据丢失的最佳实践

5.1 模式切换的规范流程

如果必须切换模式,必须按照以下流程操作:

  1. 备份所有节点的配置数据;
  2. 在测试环境验证模式切换,确保服务正常;
  3. 确认节点数是奇数(CP模式要求);
  4. 停止所有节点,统一修改所有节点的模式配置;
  5. 重启所有节点,检查集群状态;
  6. 验证所有服务的配置是否正常。

5.2 脑裂的预防措施

  1. 网络监控:监控节点之间的网络状态,一旦出现网络中断,及时告警;
  2. 节点数配置:CP模式下,节点数必须是奇数,比如3个、5个,避免选主失败;
  3. 配置中心的高可用:如果是配置中心,建议用主备模式,主节点负责写入,备节点负责读取,避免脑裂;
  4. 定期备份:定期备份Nacos的配置数据,哪怕出现脑裂,也能快速恢复。

5.3 故障恢复的应急预案

  1. 提前准备修复流程:把修复步骤整理成文档,一旦出现故障,能快速执行;
  2. 备用配置:提前准备核心配置的备份,比如订单服务、支付服务的配置,一旦丢失,能快速导入;
  3. 降级方案:如果Nacos集群不可用,能快速切换到本地配置,保证服务能用。

六、文章总结

这次踩坑,本质上是对AP、CP模式的理解不够,以及改模式的操作不规范导致的。很多人改模式的时候,只看表面的要求,比如“改个配置就行”,但忽略了模式切换的前置条件,以及集群的运行逻辑。

总结下来,模式切换不是小事,必须谨慎操作:如果是服务注册发现场景,默认的AP模式足够用,不要随便改;如果是配置中心,需要强一致性,改成CP模式前,必须做好充分的准备,包括备份、测试、节点数配置、重启整个集群。

另外,脑裂是分布式系统的常见问题,不仅Nacos会出现,Zookeeper、Redis也会出现,核心的预防措施就是保证网络稳定、节点数配置合理、提前备份数据。