分片键基数太低导致数据倾斜可快速验证:先用db.collection.distinct("shard_key_field").length检查唯一值数量,若远小于1000(百万级集合)即基数不足;再用聚合查看分布,若前10项count占比超30%则已倾斜。
分片键基数太低导致数据倾斜,怎么快速验证?
MongoDB 分片集群里,
显示某个
特别大、而其他分片几乎空着,基本就是分片键基数不足或分布不均。先确认是不是这个原因:用
查分片键的唯一值数量和分布直方图。
实操建议:
执行
—— 如果结果远小于 1000,说明基数太低(尤其当集合有百万级以上文档时)
跑个简单聚合看分布:
,如果前几项
占比超 30%,大概率已倾斜
注意:
作为默认分片键时,若应用用的是自增整数或时间戳,会天然导致写入集中在最新 chunk,这就是典型“单调递增键陷阱”
为什么 Hashed Shard Key 不总能解决问题?
Hashed 分片键(如
)能打散写入热点,但代价是牺牲范围查询能力,且对基数极低的字段无效——比如字段只有 3 个取值,哈希后还是最多 3 个 chunk,无法真正分散。
关键点:
哈希只改变分布方式,不增加基数;原始字段若只有
/
/
,哈希后仍是 3 个分片键值,数据仍卡在 3 个 chunk
所有范围查询(
)变全分片扫描,性能跳崖式下降
复合分片键中混用 hashed + ranged(如
)看似兼顾,但若
基数低,依然会聚堆——每个
的哈希值固定,其下所有
全落在同一个分片
重新选取 Shard Key 的实际操作步骤
不能直接改分片键,必须重建集合。核心是:停写 → 导出 → 新建带合理分片键的集合 → 重分片 → 导入 → 切流。
注意事项:
新分片键首选高基数、写入均匀、查询高频的字段,例如用户系统中
(UUID 或雪花 ID)比
(枚举值)靠谱得多
避免用含大量
或空字符串的字段——MongoDB 把所有
归为同一分片键值,极易倾斜
执行
前,确保该字段在所有文档中存在且类型一致;否则会报错
导入时用
,别漏掉
,否则旧数据残留引发逻辑混乱
上线后如何持续监控是否又歪了?
倾斜不是一劳永逸的事。业务增长、字段分布变化、归档策略调整都可能让原本健康的分片键逐渐失效。
盯住这几个信号:
定期跑
,重点看各分片的
数量和大小是否偏离均值 ±20%
查
(4.4+),它直接返回每分片文档数占比,比肉眼数 chunk 更准
留意
日志频率——如果某分片频繁接收 chunk 迁入,说明它正在成为“倾倒区”
特别小心 TTL 索引清理后的空洞:旧 chunk 没被及时合并,表面均衡,实际写入全挤在少数活跃 chunk,用
看
和
是否同步萎缩
分片键选得再好,也扛不住业务语义突变。比如一开始按
分片,后来发现 80% 请求来自一个 region,那这个键就废了——这时候不是调参数能救的,得回到数据模型本身。
sh.status()chunkdb.collection.aggregate()db.collection.distinct("shard_key_field").lengthdb.collection.aggregate([{$group: {_id: "$shard_key_field", count: {$sum: 1}}}, {$sort: {count: -1}}, {$limit: 10}])count_id{field: "hashed"}"A""B""C"{$gt: x, $lt: y}{tenant_id: "hashed", created_at: 1}tenant_idtenant_idcreated_atuser_idstatusnullnullsh.shardCollection("db.coll", {"new_shard_key": 1})cannot shard collection with missing or inconsistent shard key valuemongorestore --drop--dropsh.status()chunksdb.collection.getShardDistribution()moveChunksh.printShardingStatus()sizedocsregion