<返回目录     Powered by claud/xia兄

第12课: 分片集群

什么是分片?

分片(Sharding)是MongoDB的水平扩展方案,将数据分散存储在多个服务器上,突破单机存储和性能限制。

分片集群架构

分片集群包含三个组件:

1. Mongos(路由服务器)
   - 接收客户端请求
   - 路由查询到正确的分片
   - 合并多个分片的结果
   - 无状态,可以部署多个

2. Config Servers(配置服务器)
   - 存储集群元数据
   - 存储分片键范围映射
   - 必须是副本集(3个节点)

3. Shards(分片服务器)
   - 存储实际数据
   - 每个分片应该是副本集
   - 可以有多个分片

配置分片集群

// 1. 启动配置服务器(3个节点的副本集)
mongod --configsvr --replSet configRS --port 27019 --dbpath /data/config1
mongod --configsvr --replSet configRS --port 27020 --dbpath /data/config2
mongod --configsvr --replSet configRS --port 27021 --dbpath /data/config3

// 初始化配置服务器副本集
mongosh --port 27019
rs.initiate({
    _id: "configRS",
    configsvr: true,
    members: [
        { _id: 0, host: "localhost:27019" },
        { _id: 1, host: "localhost:27020" },
        { _id: 2, host: "localhost:27021" }
    ]
})

// 2. 启动分片服务器(每个分片是副本集)
// 分片1
mongod --shardsvr --replSet shard1RS --port 27017 --dbpath /data/shard1
// 分片2
mongod --shardsvr --replSet shard2RS --port 27018 --dbpath /data/shard2

// 3. 启动mongos路由服务器
mongos --configdb configRS/localhost:27019,localhost:27020,localhost:27021 --port 27016

// 4. 连接到mongos并添加分片
mongosh --port 27016
sh.addShard("shard1RS/localhost:27017")
sh.addShard("shard2RS/localhost:27018")

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

分片键

分片键决定数据如何分布到不同分片,是分片集群最重要的设计决策。

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

// 为集合创建分片键索引
db.users.createIndex({ userId: 1 })

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

分片键选择原则

分片策略

// 1. 范围分片(Range Sharding)
// 按分片键值范围分布数据
sh.shardCollection("mydb.users", { age: 1 })
// 优点:范围查询高效
// 缺点:可能数据分布不均

// 2. 哈希分片(Hashed Sharding)
// 对分片键进行哈希后分布
sh.shardCollection("mydb.users", { userId: "hashed" })
// 优点:数据分布均匀
// 缺点:范围查询需要访问所有分片

// 3. 复合分片键
// 结合多个字段
sh.shardCollection("mydb.orders", { customerId: 1, orderDate: 1 })
// 优点:更灵活的数据分布和查询优化

分片管理命令

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

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

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

// 移动chunk
sh.moveChunk("mydb.users", { userId: 12345 }, "shard2RS")

// 分割chunk
sh.splitAt("mydb.users", { userId: 50000 })

// 启用/禁用均衡器
sh.startBalancer()
sh.stopBalancer()
sh.getBalancerState()

// 设置均衡器窗口(只在特定时间运行)
db.settings.update(
    { _id: "balancer" },
    { $set: { activeWindow: { start: "23:00", stop: "06:00" } } },
    { upsert: true }
)

Chunk和均衡器

// Chunk是数据分片的基本单位
// 默认大小:64MB(可配置)

// 查看chunk分布
use config
db.chunks.find({ ns: "mydb.users" }).count()

// 修改chunk大小
db.settings.save({ _id: "chunksize", value: 128 })  // 128MB

// 均衡器自动在分片间移动chunk以保持均衡
// 触发条件:分片间chunk数量差异超过阈值

区域分片(Zone Sharding)

// 将特定数据范围分配到特定分片
// 用于地理位置隔离、硬件分级等场景

// 1. 为分片添加标签
sh.addShardTag("shard1RS", "CN")
sh.addShardTag("shard2RS", "US")

// 2. 定义区域范围
sh.addTagRange(
    "mydb.users",
    { country: "CN", userId: MinKey },
    { country: "CN", userId: MaxKey },
    "CN"
)

sh.addTagRange(
    "mydb.users",
    { country: "US", userId: MinKey },
    { country: "US", userId: MaxKey },
    "US"
)

// 中国用户数据存储在shard1,美国用户数据存储在shard2

查询路由

// 包含分片键的查询(目标查询)
// 只访问相关分片
db.users.find({ userId: 12345 })

// 不包含分片键的查询(广播查询)
// 需要访问所有分片
db.users.find({ email: "user@example.com" })

// 查看查询执行计划
db.users.find({ userId: 12345 }).explain()

// 关键指标:
// - shards: 访问的分片列表
// - nReturned: 返回的文档数
// - executionTimeMillis: 执行时间

分片集群监控

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

// 查看数据分布
db.users.getShardDistribution()

// 查看chunk迁移状态
db.adminCommand({ balancerStatus: 1 })

// 查看当前操作
db.currentOp()

// 监控关键指标:
// - 数据分布均衡度
// - chunk迁移频率
// - 查询性能
// - 分片间网络延迟

实战示例

// 电商系统分片设计
// 订单表按用户ID哈希分片
sh.enableSharding("ecommerce")
db.orders.createIndex({ userId: "hashed" })
sh.shardCollection("ecommerce.orders", { userId: "hashed" })

// 商品表按分类和商品ID复合分片
db.products.createIndex({ category: 1, productId: 1 })
sh.shardCollection("ecommerce.products", { category: 1, productId: 1 })

// 日志表按时间范围分片(配合TTL索引)
db.logs.createIndex({ timestamp: 1 })
sh.shardCollection("ecommerce.logs", { timestamp: 1 })
db.logs.createIndex({ timestamp: 1 }, { expireAfterSeconds: 2592000 })  // 30天

分片集群最佳实践

何时使用分片:
练习题:
  1. 搭建一个包含2个分片的分片集群
  2. 为用户集合选择合适的分片键并进行分片
  3. 查看数据在各分片的分布情况
  4. 测试包含和不包含分片键的查询性能
  5. 配置区域分片实现地理位置隔离
  6. 监控chunk迁移和均衡器状态