MongoDB分片 #

一、分片概述 #

1.1 什么是分片 #

分片(Sharding)是将数据分散存储在多个服务器上的方法,实现水平扩展。

text
分片集群架构
┌─────────────────────────────────────┐
│         mongos (路由)               │
│         路由查询请求                │
└──────────────┬──────────────────────┘
               │
       ┌───────┼───────┐
       ▼       ▼       ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Shard 1 │ │ Shard 2 │ │ Shard 3 │
│ (分片1) │ │ (分片2) │ │ (分片3) │
└─────────┘ └─────────┘ └─────────┘
       │       │       │
       └───────┼───────┘
               ▼
┌─────────────────────────────────────┐
│         Config Servers              │
│         存储集群元数据              │
└─────────────────────────────────────┘

1.2 分片组件 #

组件 说明
mongos 路由进程,转发客户端请求
Shard 分片服务器,存储数据子集
Config Server 配置服务器,存储集群元数据

1.3 分片优势 #

优势 说明
水平扩展 增加分片即可扩展容量
高可用 每个分片可以是复制集
负载均衡 数据自动分布到各分片
透明访问 客户端无需关心数据位置

二、分片集群部署 #

2.1 部署Config Server #

bash
# 启动Config Server(复制集)
mongod --configsvr --replSet configRs --port 27019 --dbpath /data/config

# 初始化Config Server复制集
mongosh --port 27019
rs.initiate({
    _id: "configRs",
    configsvr: true,
    members: [
        { _id: 0, host: "config1:27019" },
        { _id: 1, host: "config2:27019" },
        { _id: 2, host: "config3:27019" }
    ]
})

2.2 部署Shard #

bash
# 启动Shard(复制集)
mongod --shardsvr --replSet shard1 --port 27018 --dbpath /data/shard1

# 初始化Shard复制集
mongosh --port 27018
rs.initiate({
    _id: "shard1",
    members: [
        { _id: 0, host: "shard1-1:27018" },
        { _id: 1, host: "shard1-2:27018" },
        { _id: 2, host: "shard1-3:27018" }
    ]
})

2.3 部署mongos #

bash
# 启动mongos
mongos --configdb configRs/config1:27019,config2:27019,config3:27019 --port 27017

2.4 添加分片 #

javascript
// 连接mongos
mongosh --port 27017

// 添加分片
sh.addShard("shard1/shard1-1:27018,shard1-2:27018,shard1-3:27018")
sh.addShard("shard2/shard2-1:27018,shard2-2:27018,shard2-3:27018")

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

三、启用分片 #

3.1 启用数据库分片 #

javascript
// 启用数据库分片
sh.enableSharding("mydb")

3.2 对集合分片 #

javascript
// 对集合分片
sh.shardCollection("mydb.users", { userId: 1 })

// 使用哈希分片
sh.shardCollection("mydb.users", { userId: "hashed" })

// 使用复合分片键
sh.shardCollection("mydb.orders", { userId: 1, orderId: 1 })

3.3 查看分片状态 #

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

// 查看集合分片信息
db.users.getShardDistribution()

// 输出示例
Shard shard1 at shard1/...
    data: 100MB docs: 10000 chunks: 5
    estimated data per chunk: 20MB
Shard shard2 at shard2/...
    data: 100MB docs: 10000 chunks: 5
    estimated data per chunk: 20MB
Totals
    data: 200MB docs: 20000 chunks: 10

四、分片键 #

4.1 分片键选择 #

考虑因素 说明
基数 分片键值应该有足够的区分度
写入分布 写入应该均匀分布到各分片
查询模式 常用查询应该包含分片键
不可变性 分片键值不能修改

4.2 范围分片 #

javascript
// 范围分片
sh.shardCollection("mydb.users", { userId: 1 })

// 特点:
// - 数据按分片键值范围分布
// - 支持范围查询
// - 可能导致数据分布不均

4.3 哈希分片 #

javascript
// 哈希分片
sh.shardCollection("mydb.users", { userId: "hashed" })

// 特点:
// - 数据均匀分布
// - 不支持范围查询优化
// - 写入分布均匀

4.4 复合分片键 #

javascript
// 复合分片键
sh.shardCollection("mydb.orders", { userId: 1, createdAt: 1 })

// 特点:
// - 结合多个字段
// - 第一个字段决定分布
// - 后续字段用于范围查询

五、Chunk管理 #

5.1 Chunk概述 #

Chunk是分片的数据块,默认64MB。

text
Chunk分布
┌─────────────────────────────────────┐
│         Chunk 1: [min, 100)         │
├─────────────────────────────────────┤
│         Chunk 2: [100, 200)         │
├─────────────────────────────────────┤
│         Chunk 3: [200, 300)         │
├─────────────────────────────────────┤
│         Chunk 4: [300, max)         │
└─────────────────────────────────────┘

5.2 Chunk分割 #

javascript
// 手动分割Chunk
sh.splitAt("mydb.users", { userId: 1000 })

// 按数量分割
sh.splitFind("mydb.users", { userId: 500 })

5.3 Chunk迁移 #

javascript
// 手动迁移Chunk
sh.moveChunk("mydb.users", { userId: 1000 }, "shard2")

// 查看迁移状态
sh.isBalancerRunning()

5.4 Balancer管理 #

javascript
// 查看Balancer状态
sh.getBalancerState()

// 启用Balancer
sh.startBalancer()

// 停止Balancer
sh.stopBalancer()

// 设置Balancer窗口
db.settings.updateOne(
    { _id: "balancer" },
    { $set: { activeWindow: { start: "02:00", stop: "06:00" } } },
    { upsert: true }
)

六、分片标签 #

6.1 添加标签 #

javascript
// 为分片添加标签
sh.addShardTag("shard1", "zone1")
sh.addShardTag("shard2", "zone2")

6.2 配置标签范围 #

javascript
// 配置标签范围
sh.addTagRange(
    "mydb.users",
    { userId: MinKey },
    { userId: 1000 },
    "zone1"
)

sh.addTagRange(
    "mydb.users",
    { userId: 1000 },
    { userId: MaxKey },
    "zone2"
)

6.3 删除标签 #

javascript
// 删除标签
sh.removeShardTag("shard1", "zone1")

// 删除标签范围
sh.removeTagRange(
    "mydb.users",
    { userId: MinKey },
    { userId: 1000 }
)

七、分片查询 #

7.1 定向查询 #

javascript
// 包含分片键的查询(定向查询)
db.users.find({ userId: 123 })  // 只查询特定分片

// 包含分片键前缀的查询
db.orders.find({ userId: 123 })  // 只查询特定分片

7.2 广播查询 #

javascript
// 不包含分片键的查询(广播查询)
db.users.find({ name: "John" })  // 查询所有分片

7.3 查询优化 #

javascript
// 使用分片键优化查询
db.users.find({ userId: 123, name: "John" })

// 使用索引优化广播查询
db.users.createIndex({ name: 1 })

八、分片管理 #

8.1 添加分片 #

javascript
// 添加新分片
sh.addShard("shard3/shard3-1:27018,shard3-2:27018,shard3-3:27018")

8.2 删除分片 #

javascript
// 删除分片
sh.removeShard("shard3")

// 查看删除进度
db.adminCommand({ removeShard: "shard3" })

8.3 查看分片信息 #

javascript
// 查看分片列表
db.adminCommand({ listShards: 1 })

// 查看数据库分片信息
db.adminCommand({ enableSharding: "mydb" })

// 查看集合分片信息
db.users.getShardDistribution()

九、分片监控 #

9.1 集群状态 #

javascript
// 查看集群状态
sh.status()

// 查看详细信息
db.adminCommand({ shardingState: 1 })

9.2 Chunk统计 #

javascript
// 查看Chunk统计
db.chunks.find({ ns: "mydb.users" }).count()

// 查看Chunk分布
db.chunks.aggregate([
    { $match: { ns: "mydb.users" } },
    { $group: { _id: "$shard", count: { $sum: 1 } } }
])

9.3 Balancer状态 #

javascript
// 查看Balancer状态
sh.isBalancerRunning()
sh.getBalancerState()

// 查看迁移历史
db.changelog.find({ what: "chunk migrated" }).sort({ time: -1 }).limit(10)

十、最佳实践 #

10.1 分片键选择 #

text
分片键选择原则

1. 高基数
   - 分片键值应该有足够的区分度
   - 避免使用低基数字段(如性别)

2. 写入分布
   - 写入应该均匀分布到各分片
   - 避免使用单调递增的字段

3. 查询模式
   - 常用查询应该包含分片键
   - 减少广播查询

4. 不可变性
   - 分片键值不能修改
   - 选择稳定的字段

10.2 部署建议 #

text
生产环境部署建议

1. Config Server
   - 3个节点的复制集
   - 使用SSD存储

2. Shard
   - 每个分片是3节点复制集
   - 跨机房部署

3. mongos
   - 多个mongos实例
   - 负载均衡

4. 监控
   - 监控Chunk分布
   - 监控Balancer状态

10.3 性能优化 #

javascript
// 1. 使用合适的分片键
sh.shardCollection("mydb.users", { userId: "hashed" })

// 2. 预分割Chunk
sh.splitAt("mydb.users", { userId: 1000 })
sh.splitAt("mydb.users", { userId: 2000 })

// 3. 禁用Balancer(批量导入时)
sh.stopBalancer()
// 导入数据
sh.startBalancer()

十一、总结 #

分片操作速查表:

操作 命令
启用数据库分片 sh.enableSharding(“db”)
对集合分片 sh.shardCollection(“db.coll”, {…})
添加分片 sh.addShard(“shardRs/host:port”)
删除分片 sh.removeShard(“shard”)
查看状态 sh.status()
迁移Chunk sh.moveChunk(“ns”, {…}, “shard”)

分片键类型:

类型 说明
范围分片 按值范围分布
哈希分片 按哈希值分布
复合分片键 多字段组合

下一步,让我们学习用户权限管理!

最后更新:2026-03-27