必须先加后减并确保新节点同步完成再移除旧节点,否则副本集多数派中断导致mongos元数据只读;新节点须用备份快速恢复、配置clusterrole:configsvr、storage.engine:wiredtiger、votes:1且priority≥0.5,避免脏数据同步。

Config Server 副本集(CSRS)迁移不能“停机换盘”,必须保证任意时刻 ≥2 个可投票成员在线,否则 mongos 立即进入元数据只读状态,sh.moveChunk、sh.enableSharding 等操作全部静默失败——这不是延迟或重试问题,而是法定人数(majority)硬性中断。
为什么不能先停一个再启一个?
CSRS 是三节点副本集,多数派 = 2。若你 rs.remove() 旧节点后、新节点尚未完成同步并进入 SECONDARY 状态,副本集就只剩 1 个可投票节点,mongos 会持续拒绝元数据写入,直到下一次心跳成功且版本号更新。此时即使所有 shard 读写正常,分片管理已实质瘫痪。
- 观察
rs.status()中members[n].statestr必须是SECONDARY或PRIMARY,STARTUP2、RECOVERING、ROLLBACK都不算可用 -
mongos默认每configServerHeartbeatFrequencyMS(默认 10 秒)发心跳,但只在副本集状态满足 majority 时才刷新缓存 - 新节点加入后若未同步完 oplog,
optimeDate落后主节点 >5s,它虽在副本集中但不参与多数派计算
如何逐个替换成员而不中断 majority?
核心是“先加后减”,且新加节点必须能立即参与投票——这意味着它不能从空目录开始初始同步(太慢),而应基于最近备份快速构建可信状态。
- 在新机器上部署
mongod,配置replSet: configRepl、clusterRole: configsvr、storage.engine: wiredTiger - 启动前,用
mongorestore --drop恢复最近一次完整的config库备份(含config.databases、config.chunks等集合) - 连接当前主节点(如
10.0.1.10:27019),执行rs.add({"_id": 3, "host": "10.0.1.13:27019", "priority": 0, "votes": 1})—— 注意:不要设arbiterOnly: true,仲裁节点在 CSRS 中不允许 - 等待
rs.status()显示新节点状态为SECONDARY且optimeDate与主节点差值 ≤1s,再执行rs.remove("10.0.1.12:27019")
替换过程中哪些参数绝对不能错?
CSRS 对配置极其敏感,一个字段错误就会导致节点无法加入或被排除在 majority 外。
-
clusterRole必须为configsvr(不是shardsvr或留空),否则mongos拒绝连接 -
storage.engine必须为wiredTiger;MMAPv1 在 MongoDB 5.0+ 已弃用,且 CSRS 强制要求 WiredTiger -
members[n].buildIndexes必须为false(CSRS 成员禁止建索引),否则同步失败 -
members[n].votes和priority要匹配:若设votes: 1,则priority至少为 0.5,否则选举时可能被忽略
迁移后 mongos 不自动恢复?手动触发无效怎么办
mongos 不会主动 reload 元数据缓存,它只依赖心跳响应中的 configVersion 和 configTerm 变更。如果替换完成后仍卡在只读状态,大概率是新节点虽在线但未真正被副本集多数派认可。
- 检查
rs.status().ok是否为 1,且members[n].health === 1,statestr不是UNKNOWN - 在
mongos上执行sh.getBalancerState(),若返回false但实际想开启,说明元数据服务未就绪,不是 balancer 本身问题 - 强制刷新不可行,唯一有效路径是:确认新节点
optimeDate追平、副本集writeConcernMajorityJournalDefault为 true、且mongos心跳日志中出现"config server heartbeat succeeded"
最易被忽略的是:替换前没验证旧节点是否真的不可信。如果只是临时宕机,直接 rs.remove() 会导致干净节点被丢弃,新节点反而从一个已过期的主节点同步脏数据——务必先确认原数据目录损坏或时间戳严重滞后。











