垂直扩容在mongodb分片集群中本质是滚动替换节点而非加字段,需通过副本集冗余与mongos路由实现无感升级,严格遵循四步安全流程并谨慎管控balancer。

垂直扩容在分片集群里本质是替换节点,不是“加字段”
很多人看到“垂直扩容”第一反应是改表结构或加索引,但在 MongoDB 分片集群中,它实际指对 mongod 实例所在物理机或虚拟机升级 CPU/内存/磁盘——而整个过程必须保持集群对外服务不中断。关键在于:MongoDB 本身不支持单个 mongod 进程热升级硬件配置,只能通过“滚动替换”实现在线变更。
真正起作用的是分片集群的冗余设计:每个分片(shard)应为副本集(Replica Set),且至少有 3 个成员;同时,mongos 能自动感知成员状态变化并路由流量。只要操作符合副本集主从切换规范,就能做到用户无感。
- 必须确保目标分片的副本集
members配置中,所有节点priority和votes设置合理,避免意外降级或选举失败 - 禁止在维护期间执行
sh.stopBalancer()后长期停用均衡器——它只应在迁移 chunk 前后临时关闭,否则会导致数据分布严重倾斜 - 新节点加入前,务必用
rs.add({host: "new-host:27018", priority: 0, votes: 0})先以非投票、低优先级身份加入,同步完成后再调整角色
替换分片节点的四步安全流程
以替换某个 shard(如 shard01)中的一个延迟高、资源吃紧的 secondary 节点为例,整个过程约需 10–30 分钟,取决于 oplog 大小和网络带宽。
- 在目标副本集上执行
rs.remove("old-host:27018"),移除旧节点(确保它当前不是 primary) - 在新机器上部署同版本 MongoDB 5.0,配置相同
storage.engine、replication.replSetName和 TLS 参数,启动mongod - 连接到该副本集任意活跃节点,运行
rs.add({host: "new-host:27018", priority: 0, votes: 0}),等待stateStr变为SECONDARY且optimeDate追平 - 确认同步完成后,执行
rs.reconfig({_id: "shard01", members: [...]}, {force: true})(仅当需调整 priority/votes 时才触发 reconfig),将新节点设为可投票成员
注意:rs.reconfig() 是危险操作,必须传入完整 members 数组,不能只改单个成员字段;建议先用 rs.conf() 导出当前配置,再修改后提交。
为什么不能直接升级单个 mongod 进程?
MongoDB 5.0 的 mongod 进程绑定的是启动时的内存映射、文件句柄、WiredTiger 缓存池大小等资源,运行中无法动态扩大 wiredTiger.cacheSizeGB 或更换数据目录磁盘路径。即使你用 db.adminCommand({setParameter: 1, wiredTigerEngineConfigString: "..."})) 尝试修改,也会报错 not allowed to change at runtime。
更现实的风险是:若强行 kill -USR2 或类似信号试图 reload 配置,会导致 WiredTiger 检查点异常、journal 文件断裂,极大概率引发 WT_TRY_SALVAGE 错误甚至数据不可读。
- 唯一能运行时调整的参数极少,如
maxConns、enableLocalhostAuthBypass,不涉及底层存储层 -
setParameter对storage.wiredTiger.engineConfig.cacheSizeGB的修改在 5.0 中仍被明确拒绝,文档写明 “requires restart” - 磁盘扩容也必须停机——WiredTiger 不支持在线扩展
dataPath所在文件系统,除非你用 LVM 或云盘在线扩容底层块设备,再手动resize2fs(但这属于 OS 层操作,与 MongoDB 无关)
容易被忽略的 Balancer 与 Chunk 迁移陷阱
很多团队在换完节点后发现查询变慢、CPU 突增,排查发现是 balancer 正在疯狂迁移 chunk,而新节点磁盘 IO 跟不上,拖垮了整个 shard 的响应时间。
- 执行
sh.setBalancerState(false)后,必须紧接着用sh.getBalancerState()和sh.isBalancerRunning()双重确认已停止,因为存在几秒延迟 - 替换完所有待更新节点后,不要立刻开 balancer;先运行
sh.status()检查各 shard 的chunks数量是否均衡,再用sh.startBalancer() - 如果某 shard 的
chunk数远高于其他(比如 >2× 均值),建议先手工moveChunk几个大 chunk 到压力小的 shard,再放开 balancer,避免雪崩式迁移
真实线上环境里,一次垂直扩容最耗时的环节往往不是节点替换本身,而是 balancer 在后台默默搬数据——这个过程没有进度条,只能靠 db.changelog.find({time: {$gt: ISODate(...)}}) 查日志推断。











