chunk 是怎么拆分、怎么被 balancer 搬走的?chunk 个数不平衡算不算失衡?迁走的数据什么时候删?这篇在 2 个分片的集群上把 chunk 大小设为 1 MB,写入 60 MB 数据,观察分布变化、迁移步骤和 jumbo chunk。
# config.settings
test> db.getSiblingDB("config").settings.find()
[ { _id: 'chunksize', value: 1 } ]
[('sh0', 'sh0/127.0.0.1:9902'), ('sh1', 'sh1/127.0.0.1:9903')]刚分片的空集合只有一个 [MinKey, MaxKey) 的 chunk,在 primary 分片上;chunk 大小设成 1 MB 便于在小数据上观察。
# config.chunks
test> db.getSiblingDB("config").chunks.find({}, {_id: 0, min: 1, max: 1, shard: 1})
[ { min: { k: MinKey() }, max: { k: MaxKey() }, shard: 'sh0' } ]写入触发 chunk 分裂,balancer 同时把新 chunk 迁到另一个分片。分裂由写入流量触发:写入停止后,剩下的一个大 chunk 不会再被拆。
写入期间 chunk 分布: 0s:{'sh0': 1} → 2s:{'sh0': 1} → 4s:{'sh0': 1} → 6s:{'sh0': 1, 'sh1': 1} → 8s:{'sh0': 1, 'sh1': 3} → 10s:{'sh0': 1, 'sh1': 4}
写完时(耗时 12 s):{'sh0': 1, 'sh1': 6}最终 chunk 个数是 1 对 26,但两个分片拥有的数据量是 31.1 MB 对 28.2 MB,balancer 认为已经平衡。
写完之后: 0s:{'sh0': 1, 'sh1': 6} → 10s:{'sh0': 1, 'sh1': 14} → 20s:{'sh0': 1, 'sh1': 21} → 30s:{'sh0': 1, 'sh1': 26} → 40s:{'sh0': 1, 'sh1': 26} → 45s:{'sh0': 1, 'sh1': 26}
最终 chunk 分布 {'sh0': 1, 'sh1': 26}(chunk 个数差很多,但看数据量)
sh1:拥有 28,525 个文档 / 28.2 MB;孤儿文档 0 个 / 0.0 MB
sh0:拥有 31,475 个文档 / 31.1 MB;孤儿文档 26,312 个 / 26.0 MB
经 mongos 总数 60,000;直连分片的文档数 sh0=57,787、sh1=28,525(含孤儿文档,所以之和大于总数;mongos 会过滤孤儿)
# 孤儿文档的清理延迟(秒)
test> db.adminCommand({getParameter: 1, orphanCleanupDelaySecs: 1}).orphanCleanupDelaySecs
3600迁走的数据在源分片上不会立刻删除,直连源分片看到的文档数比 mongos 看到的多;orphanCleanupDelaySecs 默认 3600 秒。
moveChunk.from 事件共 26 条
其中一条:from sh0 → to sh1;min={'k': 259913947} max={'k': 276259863}
各步骤耗时(毫秒): step 1 of 6: 0, step 2 of 6: 0, step 3 of 6: 13, step 4 of 6: 110, step 5 of 6: 21, step 6 of 6: 91
其它字段: ['from', 'max', 'min', 'note', 'to']每次迁移在 config.changelog 里记录 6 个步骤的耗时;1 MB 的 chunk 迁移总共不到 0.25 秒。
test.j:4000 个文档(约 4 MB)全部 k = 7;chunk 数 1;其中带 jumbo 标记的 1
chunk 范围: [({'k': MinKey()}, {'k': MaxKey()}, 'sh0')]分片键全相同的数据没法拆分,chunk 超过大小上限却不能拆,被标记为 jumbo,无法被 balancer 迁移。