06. MongoDB 分片集群架构设计

MongoDB 分片集群: 分片键选择、Chunk 迁移、Balancer 与 Zone 策略

当单台 MongoDB 服务器的存储或写入能力达到瓶颈时,需要使用分片(Sharding)进行水平扩展。分片将数据分布在多个服务器上,每个分片是一个独立的复制集。

1. 分片架构

                     Client
                       │
            ┌──────────┴──────────┐
            │    mongos (路由)     │
            │   (可部署多个)       │
            └──────────┬──────────┘
                       │
            ┌──────────┴──────────┐
            │  Config Servers      │
            │  (复制集,3节点)      │
            └──────────┬──────────┘
                       │
        ┌──────────────┼──────────────┐
        │              │              │
  ┌─────▼────┐   ┌─────▼────┐   ┌─────▼────┐
  │ Shard A  │   │ Shard B  │   │ Shard C  │
  │(Replica) │   │(Replica) │   │(Replica) │
  └──────────┘   └──────────┘   └──────────┘

2. 分片键选择

2.1 分片键类型

类型特点适用场景
Range按范围分片范围查询频繁(如时间)
Hashed哈希均匀分布写密集型,避免热点
Zone数据路由到指定区域多数据中心,合规要求

2.2 分片键设计原则

// 好的分片键特征:
// 1. 高基数(cardinality)- 大量不同值
// 2. 均匀分布 - 避免热点
// 3. 查询频率高 - 常用查询条件

// ❌ 差的分片键:
db.orders.createIndex({ status: 1 });  // 只有几个值,不均匀

// ✅ 好的分片键:
db.orders.createIndex({ userId: 1, _id: 1 });
sh.shardCollection("mydb.orders", { userId: 1, _id: 1 });
// 以 userId 为主分片键(高基数),_id 作为细化

2.3 分片后查询路由

// 包含分片键的查询 → mongos 路由到指定分片(Targeted)
db.orders.find({ userId: "user123" });

// 不包含分片键的查询 → Scatter-Gather 到所有分片
// 性能下降,尽量避免
db.orders.find({ status: "completed" });

3. Chunk 与 Balancer

// Chunk 是分片内数据的逻辑单元(默认 64MB)
// Balancer 自动在分片间迁移 Chunk 以保持负载均衡

// 查看分片状态
sh.status();

// 手动移动 Chunk
sh.moveChunk("mydb.orders", { userId: "user123" }, "shard002");

// 设置 Chunk 大小
use config
db.settings.updateOne(
    { _id: "chunksize" },
    { $set: { value: 32 } },  // 32MB
    { upsert: true }
);

// 关闭 Balancer(维护时)
sh.stopBalancer();
sh.startBalancer();

4. Zone 策略

// 将特定范围的数据固定到指定分片(多数据中心场景)
sh.addShardToZone("shard000", "EU");
sh.addShardToZone("shard001", "US");

sh.updateZoneKeyRange(
    "mydb.users",
    { region: "EU", _id: MinKey },
    { region: "EU", _id: MaxKey },
    "EU"
);
// 欧洲用户数据存储在 Europe 数据中心

5. 分片扩容

1. 准备新分片服务器并启动 mongod
2. 将新分片加入集群: sh.addShard("shard4/rs0.example.com:27017")
3. Balancer 自动开始迁移 Chunk 到新分片
4. 监控迁移进度: sh.status()

6. 分片限制

功能未分片分片后
$lookup支持仅支持非分片集合
唯一索引支持必须包含分片键
$text 搜索支持不支持
多文档事务支持4.2+ 支持,但性能受影响

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「mongodb」更多文章

  1. 11. MongoDB 安全认证与备份恢复
  2. 10. MongoDB 性能调优与运维监控
  3. 09. Spring Data MongoDB 实战