执行\_sh.addshard()前必须确认:①新分片mongod已启动且监听可访问地址(非localhost);②该分片是干净、独立、已初始化的副本集(非已有分片成员);③config server健康且config.version非0。

执行 _sh.addShard() 前必须确认的三件事
MongoDB 分片集群里加新分片不是“连上就加”,_sh.addShard() 会立即触发元数据变更,但若前置条件不满足,操作会卡住、失败,甚至让已有分片不可用。
- 新分片的
mongod实例必须已启动,且监听在可被 config server 和其他 shard 访问的地址(别用localhost或127.0.0.1) - 该分片必须未启用副本集(即不能是独立
mongod),也不能是已有分片的副本集成员——它得是干净、独立、带--replSet启动的副本集,并已完成初始化(rs.initiate()) - config server 必须处于健康状态(
sh.status()能返回,且config.version不为 0),否则_sh.addShard()会报Failed to refresh metadata
执行 _sh.addShard() 的正确姿势和典型错误
直接在 mongos 上运行 _sh.addShard("rs2/10.0.1.5:27018") 是常见写法,但容易出错:
- 地址格式错:写成
"10.0.1.5:27018"(漏 replica set 名)→ 报no valid host found in replica set - 端口错:连了副本集的仲裁节点或非主节点端口 → 操作超时,
_sh.addShard()不自动重试,需手动指定主节点或等选举完成 - 权限错:当前用户没
clusterAdmin角色 → 报not authorized on admin to execute command addShard - 配置错:新分片的
storage.dbPath所在磁盘剩余空间 _sh.addShard() 本身不校验这个
成功返回类似:{ "shardAdded" : "rs2", "ok" : 1 },此时新分片已注册,但尚无数据分配给它。
数据不会自动流过去:均衡器(balancer)才是关键开关
加完分片,sh.status() 里能看到新分片,但所有 chunk 还在老分片上。真正迁移靠的是 balancer,它默认开启,但有隐含前提:
- Balancer 必须处于 active 状态:检查
sh.getBalancerState()返回true;若为false,需手动sh.setBalancerState(true) - 没有活动的维护窗口(maintenance window)禁用均衡:查
sh.getBalancerWindow(),避免在stopBalancer后忘记开 - Chunk 分布不均才触发迁移:只有当某分片 chunk 数比平均值高 > 20%(默认阈值),且目标分片低 > 20%,balancer 才开始搬;所以刚加的空分片要等“失衡”积累够才动
- 迁移过程受
moveChunk限制:单次迁移阻塞写入约几秒,大量 chunk 迁移时会影响业务延迟;可通过sh.setBalancerConfig({activeWindow:{start:"23:00",end:"06:00"}})错峰
执行中可看 sh.isBalancerRunning() 和 config DB 的 changelog 集合追踪进度。
最容易被忽略的后续动作:验证与监控
很多人以为 _sh.addShard() 成功 + balancer 开着就万事大吉,其实还有几个硬核检查点:
- 查
sh.status()中各分片的chunks数是否逐步趋近平均值;若长期不动,可能是 chunk 太小(sh.splitAt()手动切)、或存在 jumbo chunk(sh.status()里标为jumbo),它无法迁移 - 登录新分片主节点,执行
db.getSiblingDB("config").chunks.find({shard:"rs2"}).count(),确认真有 chunk 分配过去 - 监控
moveChunk日志:在 mongos 或 config server 的日志里搜moveChunk.start/moveChunk.commit,避免迁移卡在 commit 阶段(常见于网络抖动或目标分片磁盘满) - 别忘了更新应用连接字符串里的 mongos 地址列表——新加的 mongos 实例(如有)也要纳入负载均衡,否则流量压不到新分片
balancer 不是魔法,它只按规则搬 chunk;chunk 搬不动,数据就永远在老地方。










