chunkSize不能设太小,否则会因频繁分裂和迁移导致路由表更新压力大、config server元数据过载及查询延迟毛刺;默认64MB已平衡开销与均衡性,仅在明确小粒度数据或历史不均时才调整。

chunkSize 为什么不能设太小?
MongoDB 的分片集群里,chunkSize 默认是 64MB,它不是“越小越均匀”就越好。设成 16MB 甚至 1MB,短期看数据分布更细,但会立刻触发两个连锁反应:一是 mongos 路由表更新变频繁,二是 config server 上的元数据压力陡增。特别是写入密集场景,每个 chunk 满了就分裂,分裂又触发迁移,而迁移本身要锁 chunk、复制数据、更新 config 集合——这些操作在高并发下会卡住路由决策,导致查询延迟毛刺明显。
- 小于 32MB 的
chunkSize 在多数业务中属于过早优化,除非你明确知道单个 shard 上有大量 < 10MB 的热点集合,且写入集中在极少数 key 范围
- 修改后不会立即重分,已有 chunk 保持原大小,只对后续分裂生效;想快速重分布得手动
splitAt() 或 moveChunk()
-
sh.setBalancerState(false) 必须先关,否则自动均衡可能和你的手动调整冲突
怎么安全改 chunkSize?
改的是集群级配置,不是某个集合或 shard 的局部设置。执行位置必须是连接到 mongos 的 shell(不是 config server 或 shard node),且需要 clusterManager 权限。
- 连接任意
mongos,运行:sh.settings.updateOne({ _id: "chunksize" }, { $set: { value: 128 } }, { upsert: true })
- 数值单位是 MB,只接受整数,比如 128 表示 128MB
- 修改后不报错 ≠ 生效,用
sh.settings.find() 确认返回 { "_id" : "chunksize", "value" : 128 }
- 不需要重启任何进程,但新 chunk 分裂从下次满额开始才按新值计算
迁移频率太高?先看是不是 chunk 太碎,而不是急着调 balancer
自动均衡器(balancer)每 10 分钟检查一次 chunk 分布,但它只在“某 shard 的 chunk 数比平均值高出 2 个以上”时才触发迁移。如果你看到 moveChunk 日志高频出现,大概率是 chunkSize 设得太小 + 数据分布倾斜(比如时间戳做 shard key),而非 balancer 本身太激进。
- 查当前各 shard chunk 分布:
sh.status().shards.map(s => ({ name: s._id, chunks: s.chunks }))
- 如果某 shard chunk 数远高于其他(比如 500 vs 80),优先检查该 shard 上是否有未打散的大范围查询或写入热点
- 关闭 balancer 后手动迁移更可控:
sh.moveChunk("db.coll", { shardKey: value }, "targetShard"),但注意目标 shard 磁盘余量和 oplog 延迟
-
balancerStart/balancerStop 是临时开关,不影响 chunkSize 配置本身
真实场景里,什么情况下值得动 chunkSize?
绝大多数线上集群根本不需要改,默认 64MB 平衡了迁移开销和负载均衡能力。真要调,只在两种情况成立:
- 新建集群初期,已知业务数据天然粒度极小(如 IoT 设备每秒一条记录,shard key 是设备 ID + 秒级时间戳),且单设备数据日增 < 5MB,此时设 32MB 可减少未来分裂次数
- 历史遗留集群 chunk 严重不均,又不想停写做全量 dump/reload,可配合
splitVector 先把大 chunk 拆细,再调大 chunkSize 防止继续碎裂
chunkSize 在多数业务中属于过早优化,除非你明确知道单个 shard 上有大量 < 10MB 的热点集合,且写入集中在极少数 key 范围 splitAt() 或 moveChunk() sh.setBalancerState(false) 必须先关,否则自动均衡可能和你的手动调整冲突 chunkSize?
改的是集群级配置,不是某个集合或 shard 的局部设置。执行位置必须是连接到 mongos 的 shell(不是 config server 或 shard node),且需要 clusterManager 权限。
- 连接任意
mongos,运行:sh.settings.updateOne({ _id: "chunksize" }, { $set: { value: 128 } }, { upsert: true }) - 数值单位是 MB,只接受整数,比如 128 表示 128MB
- 修改后不报错 ≠ 生效,用
sh.settings.find()确认返回{ "_id" : "chunksize", "value" : 128 } - 不需要重启任何进程,但新 chunk 分裂从下次满额开始才按新值计算
迁移频率太高?先看是不是 chunk 太碎,而不是急着调 balancer
自动均衡器(balancer)每 10 分钟检查一次 chunk 分布,但它只在“某 shard 的 chunk 数比平均值高出 2 个以上”时才触发迁移。如果你看到 moveChunk 日志高频出现,大概率是 chunkSize 设得太小 + 数据分布倾斜(比如时间戳做 shard key),而非 balancer 本身太激进。
- 查当前各 shard chunk 分布:
sh.status().shards.map(s => ({ name: s._id, chunks: s.chunks }))
- 如果某 shard chunk 数远高于其他(比如 500 vs 80),优先检查该 shard 上是否有未打散的大范围查询或写入热点
- 关闭 balancer 后手动迁移更可控:
sh.moveChunk("db.coll", { shardKey: value }, "targetShard"),但注意目标 shard 磁盘余量和 oplog 延迟
-
balancerStart/balancerStop 是临时开关,不影响 chunkSize 配置本身
真实场景里,什么情况下值得动 chunkSize?
绝大多数线上集群根本不需要改,默认 64MB 平衡了迁移开销和负载均衡能力。真要调,只在两种情况成立:
- 新建集群初期,已知业务数据天然粒度极小(如 IoT 设备每秒一条记录,shard key 是设备 ID + 秒级时间戳),且单设备数据日增 < 5MB,此时设 32MB 可减少未来分裂次数
- 历史遗留集群 chunk 严重不均,又不想停写做全量 dump/reload,可配合
splitVector 先把大 chunk 拆细,再调大 chunkSize 防止继续碎裂
sh.status().shards.map(s => ({ name: s._id, chunks: s.chunks })) sh.moveChunk("db.coll", { shardKey: value }, "targetShard"),但注意目标 shard 磁盘余量和 oplog 延迟 balancerStart/balancerStop 是临时开关,不影响 chunkSize 配置本身 chunkSize?
绝大多数线上集群根本不需要改,默认 64MB 平衡了迁移开销和负载均衡能力。真要调,只在两种情况成立:
- 新建集群初期,已知业务数据天然粒度极小(如 IoT 设备每秒一条记录,shard key 是设备 ID + 秒级时间戳),且单设备数据日增 < 5MB,此时设 32MB 可减少未来分裂次数
- 历史遗留集群 chunk 严重不均,又不想停写做全量 dump/reload,可配合
splitVector先把大 chunk 拆细,再调大chunkSize防止继续碎裂
改完别只盯着迁移日志,重点看 config server 的 config.changelog 写入速率和 mongos 的 route 延迟指标——这两处才是失衡最先暴露的地方。










