升级后Balancer和AutoSplit均失效,是因为MongoDB 4.2+版本中关闭Balancer会同步禁用AutoSplit,需分别执行sh.startBalancer()和sh.enableAutoSplit()恢复完整功能。

升级后 sh.status() 显示 balancer 已关闭、autosplit 也变成 no,这不是配置遗漏,而是 MongoDB 4.2+ 的默认行为:关 Balancer 就连带关 AutoSplit。
为什么升级后 Balancer 和 AutoSplit 都失效了
从 MongoDB 4.2 开始,sh.stopBalancer()(或 sh.setBalancerState(false))不再只是暂停 chunk 迁移,它会同步禁用自动分块(auto-splitting)。这是版本级行为变更,不是 bug。
常见误判场景:
- 升级前用的是 4.0.x,关 Balancer 不影响 split,升级后照搬旧流程,结果发现新写入数据不触发 chunk 分裂,导致单个 chunk 膨胀、查询变慢
- 执行
sh.startBalancer()后,sh.status()显示 balancer 为yes,但 autosplit 仍是no—— 因为 4.2+ 要求显式启用
如何恢复 Balancer + AutoSplit 的完整功能
必须分两步操作,缺一不可:
- 先启用 Balancer:
sh.startBalancer()或sh.setBalancerState(true) - 再单独启用 AutoSplit:
sh.enableAutoSplit()
验证是否生效:
mongos> sh.status() ... autosplit: Currently enabled: yes balancer: Currently enabled: yes Currently running: no
注意:sh.enableAutoSplit() 在 6.0.3+ 版本中已无实际作用(官方已弃用自动分裂逻辑),但 4.2–6.0.2 之间仍需调用;若集群是 6.0.3+,则只需确保 Balancer 开启,split 行为由新均衡策略接管。
升级过程中 Balancer 状态被意外锁定怎么办
有时升级后 sh.getBalancerState() 返回 true,但 sh.isBalancerRunning() 一直为 false,且 sh.status() 中显示 Currently running: no —— 这通常意味着 Balancer 线程卡在锁状态或配置服务器元数据未刷新。
可尝试以下操作:
- 强制刷新配置缓存:
db.adminCommand({flushRouterConfig: 1}) - 检查 config server 是否全部可达:
sh.status()中的config servers段应显示健康副本集 - 确认没有残留的 balancer 锁文档:
db.getSiblingDB("config").locks.find({ _id: "balancer" }),若state字段为2(locked)且who字段为空或过期,可手动清理(仅限紧急情况,需确保无其他 mongos 正在运行)
升级后删减分片失败,总是卡在“等待 chunk 迁出”
这不是 Balancer 没开,而是它开了却没干活 —— 很可能掉进了“活动窗口期(balance window)”陷阱。
即使 sh.getBalancerState() 返回 true,如果当前时间不在 balance.window 设定范围内,Balancer 也不会启动迁移轮次。
检查和修复方法:
- 查当前窗口:
sh.getBalancerWindow(),返回类似{ "start": "22:00", "stop": "04:00" } - 临时扩大窗口(维护期间):
sh.setBalancerWindow("00:00", "23:59") - 确认窗口已生效:
sh.getBalancerWindow()再查一次
注意:MongoDB 8.0+ 的 sh.setBalancerWindow() 参数格式为字符串,不能传 Date 对象或毫秒数;且该设置只对当前 mongos 会话有效,建议在所有 mongos 上都执行一遍。
真正容易被忽略的点是:Balancer 状态正常 ≠ 迁移正在发生。它受窗口期、chunk 分布差值阈值、shard tag 约束三重控制,其中窗口期最隐蔽 —— 尤其跨时区部署时,start/stop 时间按 UTC 解析,而运维人员常按本地时间理解。











