movePrimary仅更新元数据不迁移数据,磁盘满时虽能成功但后续写入会失败;必须先清理空间、再执行movePrimary、最后触发均衡或手动moveChunk。

磁盘满时 movePrimary 会直接失败
movePrimary 不是数据迁移命令,它只修改 config 数据库里 database 集合中对应库的 primary 字段,不搬运任何文档。如果目标分片磁盘已满,movePrimary 本身能执行成功(因为不写数据),但后续所有对该库的写入都会因目标分片无法分配新 chunk 而卡住,报错类似 Failed to create new chunk: couldn't allocate space。此时看似“平滑”,实则埋雷。
真正要做的:先腾空间,再改 primary,最后触发 chunk 迁移
必须分三步走,缺一不可:
- 在磁盘满的分片上,用
db.collection.drop()或db.collection.remove({})清理非关键集合;或用mongod --repair(需停机)回收已删除文档的磁盘空间 - 确认目标分片有足够空闲空间(建议 ≥ 当前库数据量 × 1.2),且
sh.status()显示其状态为ONLINE - 执行
sh.movePrimary("dbname", "shard0001")—— 此时只是更新元数据,不移动数据 - 手动触发均衡:运行
sh.startBalancer()(若已关闭),或等待自动均衡器发现该库的 chunk 分布不均后拉取数据
movePrimary 后 chunk 不动?检查这几个配置
常见现象:primary 已切到新分片,但所有 chunk 还留在旧分片,读写压力没转移。原因通常是:
- 目标分片的
maxSize设置过小(默认 64MB),导致 chunk 拆分失败,无法迁移 —— 检查sh.getShardDistribution("dbname")输出中的maxSize值 - 均衡器被禁用:
sh.getBalancerState()返回false,需手动sh.setBalancerState(true) - 存在未完成的迁移任务:
db.changelog.find({ "what": "moveChunk" }).sort({ time: -1 })查看最近失败记录,常见错误如cannot move chunk: failed to clone,多因网络中断或目标分片 I/O 阻塞
更稳妥的替代方案:直接用 moveChunk 控制粒度
当磁盘极度紧张、不能等均衡器慢慢搬时,跳过 movePrimary,改用 moveChunk 手动逐个迁移大 chunk:
sh.moveChunk("dbname.collectionname", { _id: ObjectId("...") }, "shard0001")
注意:
- 必须指定一个合法的
min键值(如{ _id: ObjectId("...") }),不能传空对象 - 每次只迁一个 chunk,避免并发写入冲突;迁移期间该 chunk 范围写入会短暂阻塞
- 迁移前用
db.collection.getShardVersion()确认集合当前分片版本,防止元数据不一致
movePrimary 是元数据开关,不是迁移开关;真正搬数据的是均衡器或 moveChunk —— 这个分工容易被忽略,一上来就 runCommand,结果磁盘还是满的。











