分片集群问题

最近更新时间:2026-06-22 15:56:00

我的收藏
本文汇总云数据库 MongoDB 分片集群在创建、扩容、片键设计、预分片、查询优化与孤儿文档处理等方面的高频问题。

什么是 MongoDB 分片集群?

分片集群将数据按片键(Shard Key)分散存储到多个分片(Shard)上,提供近乎线性的横向扩展能力,适用于 TB - PB 级的海量数据存储场景。
每个分片本身是一个多节点副本集,片内自动容灾,保障高可用。
支持实例级别的备份与回档,保障数据可靠。
通过 mongos 路由层对外提供统一访问入口。

如何创建 MongoDB 分片集群?

MongoDB 购买页 将实例类型选择为分片集群,按需设置分片数量、片内节点数和节点规格即可。每个分片均为多节点副本集,片内自动容灾。

如何查看分片集群的信息?

在控制台实例管理页可查看分片构成、各分片节点规格与已用容量,并可进行续费、扩容等操作。

分片集群支持哪些扩容方式?

支持两种扩容思路:
纵向扩容:在控制台对所有分片节点统一提升规格(CPU/内存/磁盘)。
横向扩容:增加分片数量,将数据进一步分散以扩展存储和写入能力。
在控制台实例列表页单击配置调整即可操作。

分片集群支持哪些分片策略?

哈希分片(Hashed):按片键哈希值均匀分布数据,适合高频指定值查询、写入需均衡的场景。
范围分片(Ranged):按片键取值范围分布数据,适合高频范围查询的场景。
支持单字段片键,也支持联合字段片键。
说明:
分片实例下的集合需启用分片;不分片的数据建议放到独立的副本集实例中。

如何选择合适的片键?

片键对分片集群读写性能至关重要,低版本一旦设置不可修改,选择应遵循:
1. 保证写入数据能均衡散列到各分片,避免热点分片。
2. 尽量让高频查询命中单个分片,避免 mongos 跨分片聚合。
3. 高频范围查询优先选用范围分片。
4. 高频指定查询优先选用哈希分片。

如何进行提前预分片?

预分片可让数据从一开始就均衡写入多个分片,避免业务高峰期因 chunk 不均触发 moveChunk 引起的抖动。
哈希预分片n 为分片数):
sh.shardCollection("db.collection", {bookId: "hashed"}, false, { numInitialChunks: 8192 * n })
设置 Balancer 窗口(建议在业务低峰期执行数据均衡):
use config
db.settings.update({"_id":"balancer"}, {"$set":{"activeWindow":{"start":"02:00","stop":"05:00"}}}, true)

查询不带片键导致性能差,如何优化?

携带片键的查询可直接定位到对应分片,性能最优;不带片键的查询会广播到所有分片再由 mongos 聚合,效率较低。
优化方案:建立辅助索引表。 当集群分片较多、不带片键的查询又很频繁时,可额外维护一张以高频查询字段为片键的辅助表,通过两次查询替代全分片广播。
示例:主表 feed_infouserId 为片键,但业务也高频按 feedId 查询。可引入辅助表 feedId_userId_relationship(以 feedId 为片键):
// 先查辅助表获取 userId
db.feedId_userId_relationship.find({"feedId": "223"}, {userId: 1}) // 返回 userId: "3445"
// 再用片键查主表
db.feed_info.find({"userId": "3445"})
说明:
辅助表会增加存储成本和一次额外查询,建议仅在分片多、不带片键查询频繁的场景使用。

什么是孤儿文档?如何清理?

在分片集群中,因数据迁移或异常中断,可能出现某文档已复制到目标分片但未从源分片删除的情况,导致同一文档存在于两个分片中。Config Server 只记录其归属分片,另一分片上的冗余文档不被感知,后续 update/delete 不会作用于它,这类文档称为孤儿文档(Orphaned Document)
清理方式按版本区分:
MongoDB 4.4及以上:数据块迁移完成后,系统会自动执行范围删除(range deletion)清理孤儿文档,通常无需手动干预;如需手动清理,可在分片的主节点上执行 cleanupOrphaned 命令。详见 cleanupOrphaned(v4.4)
MongoDB 4.4以下:不会自动清理,需手动在各分片的主节点(shard primary)上执行 cleanupOrphaned 命令。详见 cleanupOrphaned(v4.2)