sh.addShard()仅注册分片不迁移数据,新分片空转属正常现象;需确保均衡器开启且chunk差异超阈值(默认8)才会触发迁移,多级扩容必须每次只加1个分片,避免balancer过载和路由错误。

sh.addShard()本身不迁移数据,新分片长期空转是常态——这不是操作失败,而是你没触发均衡逻辑。
sh.addShard()只注册,不搬数据
执行sh.addShard("rs4/mongo04:27018")后,sh.status()里能看到新分片,但chunks和docs仍为0。这是因为:
- 均衡器(balancer)必须处于开启状态:
sh.getBalancerState()返回true;若为false,先运行sh.setBalancerState(true) - 已有分片间的 chunk 数量差异必须超过阈值(默认 8),否则 balancer 认为“够均衡”,压根不启动迁移
- 新分片不会主动抢流量,只等 balancer 按策略调度 moveChunk —— 这个过程可能耗时数小时,尤其当 chunk 总量少或写入不活跃时
多级扩容必须单次加 1 个分片
一次性执行多次sh.addShard()(比如连加 3 个)极易引发问题:
- balancer 同时处理多个迁移任务,oplog 压力飙升,secondary 落后严重
- 出现
Failed to route to shard for transaction错误,mongos 无法定位目标分片 - chunk 迁移队列堆积,部分迁移卡在
moveChunk.ongoing状态长达数小时 - 生产环境务必等
sh.status()显示各分片chunks数值接近(方差 balancer日志无活跃迁移记录,再加下一个
新分片“零数据”的真实原因常被误判
即使 balancer 开着、chunk 差异也超阈值,新分片还是没数据?重点排查:
- 分片键设计是否导致数据天然倾斜:比如用
_id(ObjectID)范围分片,所有新写入都落在最大时间戳区间,老分片持续承接,新分片永远等不到边界拆分点 - 集合是否尚未触发自动拆分:全量数据还挤在 1 个 chunk 里,根本没法跨分片分配;可用
sh.splitAt("db.coll", {_id: ObjectId("...")})手动预拆 - 是否曾执行
sh.disableAutoSplit("db.coll")且未恢复:这会让 chunk 固化,必须配对调用sh.enableAutoSplit("db.coll") - 新分片是否以
shardsvr模式启动:若只是普通 mongod,addShard会拒绝;检查配置中是否有--shardsvr或sharding.clusterRole: shardsvr
想定向引流?得靠 zone + moveChunk
如果目标是让某段时间的数据(如 2026Q2)只写入新分片shard04,sh.addShard()完全不够:
- 先定义 zone:
sh.addTagRange("db.coll", {ts: MinKey}, {ts: ISODate("2026-04-01")}, "q1_2026") - 绑定分片与 zone:
sh.addShardToZone("shard04", "q1_2026") - 确保分片键包含
ts字段且已建索引,否则 zone 规则不生效 - zone 不影响已有数据分布,只约束后续插入和迁移;已有数据需配合
moveChunk手动调整
真正难的不是加节点,而是让数据按预期流过去——分片键选型、chunk 拆分节奏、zone 策略,三者缺一不可。

















