balancer未启用时需先用sh.getbalancerstate()确认开关状态,返回false即被关闭;即使启用也受维护窗口限制,需检查sh.getbalancerwindow();若运行中却停滞,则排查jumbo chunk、磁盘空间、集合级禁用或config server锁异常。

Balancer根本没启用:先确认开关状态
最常见的情况是 sh.getBalancerState() 返回 false,意味着 Balancer 被人为关闭或从未开启。它不会自动启动,必须显式启用。
- 检查方式:在
mongos上运行sh.getBalancerState(),不是mongod;若返回false,说明已停用 - 控制台参数页查
openBalance.window,值为false也等价于关闭 - 误操作高发点:备份、升级或人工维护后忘记
sh.startBalancer() - 注意:
sh.isBalancerRunning()返回false不一定代表没启用——它只反映“当前是否正在迁移”,而sh.getBalancerState()才是真开关
Balancer开着但不动:检查活动窗口期
即使 sh.getBalancerState() 是 true,Balancer 也可能因时间窗限制无法工作。它的迁移行为严格受 balance.window 控制,不是全天候运行。
- 执行
sh.getBalancerWindow(),返回类似{"start":"00:30","stop":"02:30"}—— 如果当前时间不在这个区间,Balancer 就“静默” - 窗口过窄(如仅 30 分钟)会导致迁移极慢,尤其 Chunk 数量大时,可能卡在“已启用但不干活”状态
- 修改方式:用
db.settings.updateOne({ _id: "balancer" }, { $set: { activeWindow: { start: "22:00", stop: "06:00" } } }),注意格式是"HH:MM",不带秒 - 别依赖默认窗口:某些云厂商控制台会预设空窗口或极小窗口,需手动覆盖
Balancer在跑但进度停滞:查 Chunk 分布与迁移卡点
出现 sh.isBalancerRunning() 为 true,但 sh.status() 显示某分片长期 “chunks: 1” 或 “no chunks”,说明迁移被阻塞,不是没启动。
- 先查目标分片剩余 Chunk 数:在从节点上运行
db.getSiblingDB("config").chunks.aggregate([{$match:{shard:"cmgo-xxxxxxxx_4"}},{$group:{_id:null,count:{$sum:1}}}]) - 再查最近迁移记录:用
db.getSiblingDB("config").changelog.aggregate([{$match:{time:{$gt:ISODate("2026-07-20T00:00:00Z")},what:"moveChunk"}},{$count:"moved"}]) - 常见卡点:目标分片磁盘满、网络分区、源/目标分片版本不一致、某个集合被
sh.disableBalancing("db.coll")单独禁用 - 特别注意:
sh.balancerCollectionStatus("db.coll")返回"balancerCompliant": false表示该集合当前不满足均衡条件(比如 chunk size 远超 128MB 且无法 split)
Balancer异常退出或被干扰:看 config server 日志和锁状态
从 MongoDB 7.0 起,Balancer 进程运行在 config server 主节点上,不再由 mongos 驱动。如果 config server 主节点切换或日志报错,Balancer 可能无声终止。
- 登录 config server 主节点,查
mongod日志中是否有balancer相关 ERROR 或 WARNING,关键词包括Failed to acquire balancer lock、Could not refresh cluster metadata - 检查锁表:
db.getSiblingDB("config").locks.findOne({ _id: "balancer" }),若state为2(locked)但who字段为空或过期进程名,说明锁残留 - 不要直接删锁文档——应先确认无活跃迁移,再用
sh.stopBalancer()+sh.startBalancer()触发锁重置 - 云环境特例:Atlas 的 M0/Flex 集群根本不支持
sh.stopBalancer(),遇到问题只能提工单,本地排查无效
sh.status() 输出里的 currently-running 和 currently-enabled 两字段是否同时为 true,再决定往哪一层深挖。











