bigywater.tech
MongoDB · 75

hashed 分片与 ranged 分片的 chunk 分布

哈希分片键和 ranged 分片键,chunk 是怎么分布的?哈希一定均匀吗?这篇用连续键、随机键、热点键三种数据在两个分片上逐个看。

30,451 对 29,549
60,000 个连续键在哈希分片集合上两个分片拥有的文档数
60,000 对 0
同样的连续键在 ranged 分片集合上两个分片拥有的文档数
85%
70% 文档同一个键值时,最大 chunk 占的文档比例

哈希的初始 chunk

实测 · 本机执行输出
  chunk 分布 {'sh0': 1, 'sh1': 1};范围:
    sh0  [{'k': MinKey()}, {'k': 0})
    sh1  [{'k': 0}, {'k': MaxKey()})

哈希分片集合在建立时就按哈希空间(以 0 为界)给每个分片一个 chunk。

numInitialChunks

实测 · 本机执行输出
  chunk 分布 {'sh0': 1, 'sh1': 1};全部范围:
    sh0  [{'k': MinKey()}, {'k': 0})
    sh1  [{'k': 0}, {'k': MaxKey()})

numInitialChunks=8 在这个版本上实测没有生效,chunk 仍是 2 个,要用 config.chunks 核对。

连续键

实测 · 本机执行输出
  hashed:各分片拥有的文档数 {'sh0': 30451, 'sh1': 29549}
  ranged:各分片拥有的文档数 {'sh0': 60000};chunk 分布 {'sh0': 1}

哈希把连续键均匀打散(30,451 对 29,549);ranged 的连续键全挤在一个 chunk 里(60,000 对 0)。

随机键

实测 · 本机执行输出
  写完后(balancer 关着):chunk 分布 {'sh0': 1};拥有文档 {'sh0': 60000}
  balancer 开了 10 秒后:chunk 分布 {'sh0': 1, 'sh1': 3};拥有文档 {'sh1': 22956, 'sh0': 37044}

ranged 集合上随机键开始也都在一个 chunk,但 balancer 拆分并迁移后能分开(37,044 对 22,956)。

热点键

实测 · 本机执行输出
  各分片拥有的文档数 {'sh1': 9016, 'sh0': 50984}
  每个 chunk 的文档数 (分片, 数量): [('sh0', 50984), ('sh1', 9016)]
  最大的一个 chunk 有 50,984 个文档(85%),在 sh0 上;哈希把 k = 42 的所有文档映射到同一个哈希值,只能落在同一个 chunk 里

哈希只能打散不同的键值,同一个键值始终映射到同一个哈希值、同一个 chunk:70% 文档同一个 k,85% 的文档就在一个分片上。

路由

实测 · 本机执行输出
  hot 集合 k = 42 → ['sh0'];k = 43 → ['sh1'];k ∈ [40, 50) → ['sh0', 'sh1'];k $in [1, 2, 3, 4] → ['sh0', 'sh1']

哈希键的等值查询 targeted 到一个分片,范围与 $in 多值要问多个分片。

分步演示

哈希与 ranged 的 chunk 分布
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / MongoDB 9.0.2(Homebrew 的 mongod、mongos)/ mongosh 2.12.0 / pymongo 4.18.3;每个实验在临时目录里起全新的 mongod(独立 dbpath,端口 9900 以上,只监听 127.0.0.1,WiredTiger 缓存 0.25 GB),需要副本集或分片集群时在本机起多个进程;命令输出来自真实的 mongosh,批量写入、计时与多线程用 pymongo;计时用 time.perf_counter,数字每次运行会有小幅抖动,ObjectId、时间戳等每次运行都不同。2 个分片,chunk 1 MB,balancer 在大部分对比里关着
    • 没有验证:numInitialChunks 为什么没有生效(可能与版本或集合状态有关,没有查明);presplitHashedZones;数据倾斜在 zone sharding 下的表现;复合哈希键;热点键加随机后缀的办法;chunk 数很多时 mongos 路由缓存的开销
    京ICP备2026067502号-1京公网安备11010502063487号