写在前面:当数据量达到单节点无法承载时,MongoDB的分片集群提供了水平扩展能力。本篇将详细介绍分片集群的原理、部署和管理,帮助您轻松应对亿级数据挑战。
文章目录
-
- 一、分片集群基础
-
- [1.1 什么是分片?](#1.1 什么是分片?)
- [1.2 分片集群架构](#1.2 分片集群架构)
- [1.3 集群组件](#1.3 集群组件)
- 二、分片键选择
-
- [2.1 分片键概念](#2.1 分片键概念)
- [2.2 分片键原则](#2.2 分片键原则)
- [2.3 常见分片键策略](#2.3 常见分片键策略)
- 三、部署分片集群
-
- [3.1 环境准备](#3.1 环境准备)
- [3.2 部署步骤](#3.2 部署步骤)
- [3.3 添加分片](#3.3 添加分片)
- 四、分片操作
-
- [4.1 启用分片](#4.1 启用分片)
- [4.2 查看分片状态](#4.2 查看分片状态)
- [4.3 数据均衡](#4.3 数据均衡)
- 五、查询与写入
-
- [5.1 路由查询](#5.1 路由查询)
- [5.2 聚合管道](#5.2 聚合管道)
- 六、运维管理
-
- [6.1 添加/移除分片](#6.1 添加/移除分片)
- [6.2 分割块](#6.2 分割块)
- [6.3 移动块](#6.3 移动块)
- 七、性能优化
-
- [7.1 分片键优化](#7.1 分片键优化)
- [7.2 索引优化](#7.2 索引优化)
- 八、备份与恢复
-
- [8.1 备份](#8.1 备份)
- [8.2 恢复](#8.2 恢复)
- 九、常见问题
- 十、总结
一、分片集群基础
1.1 什么是分片?
📚 分片概念:
分片(Sharding)是MongoDB的水平扩展方案,
将数据分散存储在多个节点上。
优点:
✅ 支持海量数据存储
✅ 高并发读写能力
✅ 负载均衡
✅ 容错性高
1.2 分片集群架构
🏗️ 分片集群结构:
┌──────────────┐
│ Router │
│ mongos │
└──────┬───────┘
│
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Config │ │ Config │ │ Config │
│ Server │ │ Server │ │ Server │
│ (配置) │ │ (配置) │ │ (配置) │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Shard1 │ │ Shard2 │ │ Shard3 │
│ (分片1) │ │ (分片2) │ │ (分片3) │
└──────────┘ └──────────┘ └──────────┘
1.3 集群组件
| 组件 | 说明 | 数量 |
|---|---|---|
| mongos | 路由节点,转发请求 | >=1 |
| config server | 配置服务器,存储元数据 | 3(副本集) |
| shard | 分片节点,存储数据 | >=1 |
二、分片键选择
2.1 分片键概念
javascript
// 分片键决定数据分布
// 选择合适的分片键至关重要
// 示例:按userId分片
sh.shardCollection("myapp.orders", { userId: 1 })
// 复合分片键
sh.shardCollection("myapp.events", { eventType: 1, timestamp: -1 })
2.2 分片键原则
🎯 分片键选择原则:
✅ 基数性高
- 分片键值数量要多
- 如:ObjectId > 用户ID > 性别
✅ 分布均匀
- 避免数据倾斜
- 避免热点数据
✅ 查询友好
- 常用查询条件包含分片键
- 支持范围查询
❌ 避免
- 低基数字段(如性别)
- 单一值(如常量)
- 频繁更新的字段
2.3 常见分片键策略
javascript
// 1. 用户ID分片(最常用)
sh.shardCollection("myapp.orders", { userId: 1 })
// 2. 时间分片(时序数据)
sh.shardCollection("myapp.logs", { timestamp: 1 })
// 3. 哈希分片(均匀分布)
sh.shardCollection("myapp.products", { _id: "hashed" })
// 4. 复合分片键(复合场景)
sh.shardCollection("myapp.events", {
eventType: 1,
userId: 1,
timestamp: -1
})
三、部署分片集群
3.1 环境准备
bash
# 假设5台服务器:
# 192.168.1.10 - mongos
# 192.168.1.11 - config server (副本集)
# 192.168.1.12 - config server
# 192.168.1.13 - config server
# 192.168.1.20 - shard1 (副本集)
# 192.168.1.21 - shard1
# 192.168.1.22 - shard2 (副本集)
# 192.168.1.23 - shard2
# 192.168.1.30 - shard3 (副本集)
# 192.168.1.31 - shard3
3.2 部署步骤
bash
# 1. 启动Config Server副本集
mongod --configsvr --replSet configReplSet \
--port 27019 --dbpath /data/config \
--bind_ip 0.0.0.0
# 2. 初始化Config Server副本集
mongosh --port 27019
rs.initiate({
_id: "configReplSet",
members: [
{ _id: 0, host: "192.168.1.11:27019" },
{ _id: 1, host: "192.168.1.12:27019" },
{ _id: 2, host: "192.168.1.13:27019" }
]
})
# 3. 启动Shard节点(每个分片都是副本集)
mongod --shardsvr --replSet shard1 \
--port 27018 --dbpath /data/shard1 \
--bind_ip 0.0.0.0
# 4. 启动mongos路由
mongos --configdb configReplSet/192.168.1.11:27019,192.168.1.12:27019,192.168.1.13:27019 \
--port 27017 --bind_ip 0.0.0.0
3.3 添加分片
javascript
// 连接到mongos
mongosh --port 27017
// 添加分片
sh.addShard("shard1/192.168.1.20:27018,192.168.1.21:27018")
sh.addShard("shard2/192.168.1.22:27018,192.168.1.23:27018")
sh.addShard("shard3/192.168.1.30:27018,192.168.1.31:27018")
// 查看分片状态
sh.status()
四、分片操作
4.1 启用分片
javascript
// 1. 启用数据库分片
sh.enableSharding("myapp")
// 2. 对集合分片
sh.shardCollection("myapp.users", { userId: 1 })
// 3. 哈希分片
sh.shardCollection("myapp.products", { _id: "hashed" })
4.2 查看分片状态
javascript
// 查看集群状态
sh.status()
// 详细分片信息
db.getSiblingDB("config").shards.find().pretty()
// 查看集合分片信息
db.getSiblingDB("config").collections.find({ _id: "myapp.users" })
4.3 数据均衡
javascript
// 查看块分布
db.getSiblingDB("config").chunks.find({ ns: "myapp.users" }).pretty()
// 手动均衡(通常自动处理)
sh.startBalancer()
// 停止均衡
sh.stopBalancer()
// 查看均衡器状态
sh.getBalancerState()
五、查询与写入
5.1 路由查询
javascript
// 分片键查询 - 高效(直接定位)
db.orders.find({ userId: "user123" })
// 非分片键查询 - 全部分片扫描(效率低)
db.orders.find({ orderId: "O001" })
// 混合查询
db.orders.find({
userId: "user123",
status: "completed"
})
// 先定位user123的分片,再过滤status
5.2 聚合管道
javascript
// 分片聚合
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$userId", total: { $sum: "$total" } } },
{ $sort: { total: -1 } },
{ $limit: 10 }
])
// mongos会并行从各分片获取数据并合并
六、运维管理
6.1 添加/移除分片
javascript
// 添加新分片
sh.addShard("shard4/192.168.1.40:27018,192.168.1.41:27018")
// 移除分片(数据会自动迁移)
sh.removeShard("shard4")
// 查看移除状态
db.getSiblingDB("admin").runCommand({ removeShard: "shard4" })
6.2 分割块
javascript
// 手动分割块(用于预分割)
sh.splitAt("myapp.users", { userId: "user500" })
// 找到块的中间点并分割
sh.splitFind("myapp.users", { userId: "user250" })
6.3 移动块
javascript
// 手动移动块(均衡负载)
sh.moveChunk(
"myapp.users",
{ userId: "user500" },
"shard4"
)
七、性能优化
7.1 分片键优化
javascript
// 场景:用户订单查询
// 按userId分片,查询单个用户订单高效
sh.shardCollection("myapp.orders", { userId: 1, orderId: 1 })
// 需要按时间范围查询?考虑时间分片
// 但会导致热点问题,需要权衡
7.2 索引优化
javascript
// 每个分片都需要创建索引
// 在mongos上创建,会同步到所有分片
db.orders.createIndex({ userId: 1, status: 1 })
db.orders.createIndex({ createdAt: -1 })
八、备份与恢复
8.1 备份
bash
# 备份整个集群
# 需要备份每个分片和配置服务器
# 备份单个分片
mongodump --host 192.168.1.20 --port 27018 \
--db myapp --out /backup/shard1/
# 备份配置服务器
mongodump --host 192.168.1.11 --port 27019 \
--db config --out /backup/config/
8.2 恢复
bash
# 恢复到分片集群
# 1. 恢复配置
mongorestore --host 192.168.1.11 --port 27019 \
--config /backup/config/
# 2. 恢复各分片
mongorestore --host 192.168.1.20 --port 27018 \
--db myapp /backup/shard1/myapp/
九、常见问题
❓ 分片常见问题:
1. 热点数据
- 原因:分片键选择不当
- 解决:重新选择分片键,使用哈希分片
2. 数据倾斜
- 原因:分片键分布不均
- 解决:使用复合分片键,调整块大小
3. 查询效率低
- 原因:未使用分片键
- 解决:查询条件包含分片键
4. 集群不可用
- 原因:config server故障
- 解决:确保config server副本集健康
十、总结
📊 本篇总结:
✅ 掌握内容:
- 分片集群基础概念
- 分片键选择策略
- 分片集群部署
- 分片操作与管理
- 查询与写入机制
- 运维管理
- 性能优化
- 备份恢复
作者 :刘~浪地球
更新时间 :2026-05-10
本文声明:原创不易,转载需授权!