MongoDB 分片集群搭建教程
当单个 MongoDB 副本集 的存储容量或读写性能达到瓶颈时,分片(Sharding)是实现水平扩展的解决方案。分片将数据分散到多个分片服务器上,每个分片只存储数据的一部分,从而突破单节点的限制。本文将在搬瓦工 VPS 上演示一个最小化的分片集群搭建流程。
一、分片集群架构
MongoDB 分片集群由三种组件组成:
- Shard(分片服务器):存储实际数据。每个分片本身就是一个副本集,提供高可用。
- Config Server(配置服务器):存储集群元数据和分片路由信息。也是一个副本集。
- Mongos(路由):客户端的入口点,将请求路由到正确的分片。无状态,可以部署多个。
本教程搭建包含 2 个分片的最小集群。为简化演示,将在同一台 VPS 上使用不同端口模拟。生产环境应分别部署在独立服务器上。
二、环境规划
# Config Server 副本集 (configRS)
# 端口: 27019, 27020, 27021
# Shard 1 副本集 (shard1RS)
# 端口: 27101, 27102, 27103
# Shard 2 副本集 (shard2RS)
# 端口: 27201, 27202, 27203
# Mongos 路由
# 端口: 27017
创建数据目录:
mkdir -p /data/mongodb/{config1,config2,config3}
mkdir -p /data/mongodb/{shard1a,shard1b,shard1c}
mkdir -p /data/mongodb/{shard2a,shard2b,shard2c}
mkdir -p /var/log/mongodb
三、启动 Config Server 副本集
# 启动三个 Config Server
mongod --configsvr --replSet configRS --port 27019 --dbpath /data/mongodb/config1 --logpath /var/log/mongodb/config1.log --fork --bind_ip_all
mongod --configsvr --replSet configRS --port 27020 --dbpath /data/mongodb/config2 --logpath /var/log/mongodb/config2.log --fork --bind_ip_all
mongod --configsvr --replSet configRS --port 27021 --dbpath /data/mongodb/config3 --logpath /var/log/mongodb/config3.log --fork --bind_ip_all
初始化 Config Server 副本集:
mongosh --port 27019 --eval '
rs.initiate({
_id: "configRS",
configsvr: true,
members: [
{ _id: 0, host: "localhost:27019" },
{ _id: 1, host: "localhost:27020" },
{ _id: 2, host: "localhost:27021" }
]
})'
四、启动 Shard 副本集
4.1 Shard 1
mongod --shardsvr --replSet shard1RS --port 27101 --dbpath /data/mongodb/shard1a --logpath /var/log/mongodb/shard1a.log --fork --bind_ip_all
mongod --shardsvr --replSet shard1RS --port 27102 --dbpath /data/mongodb/shard1b --logpath /var/log/mongodb/shard1b.log --fork --bind_ip_all
mongod --shardsvr --replSet shard1RS --port 27103 --dbpath /data/mongodb/shard1c --logpath /var/log/mongodb/shard1c.log --fork --bind_ip_all
mongosh --port 27101 --eval '
rs.initiate({
_id: "shard1RS",
members: [
{ _id: 0, host: "localhost:27101" },
{ _id: 1, host: "localhost:27102" },
{ _id: 2, host: "localhost:27103" }
]
})'
4.2 Shard 2
mongod --shardsvr --replSet shard2RS --port 27201 --dbpath /data/mongodb/shard2a --logpath /var/log/mongodb/shard2a.log --fork --bind_ip_all
mongod --shardsvr --replSet shard2RS --port 27202 --dbpath /data/mongodb/shard2b --logpath /var/log/mongodb/shard2b.log --fork --bind_ip_all
mongod --shardsvr --replSet shard2RS --port 27203 --dbpath /data/mongodb/shard2c --logpath /var/log/mongodb/shard2c.log --fork --bind_ip_all
mongosh --port 27201 --eval '
rs.initiate({
_id: "shard2RS",
members: [
{ _id: 0, host: "localhost:27201" },
{ _id: 1, host: "localhost:27202" },
{ _id: 2, host: "localhost:27203" }
]
})'
五、启动 Mongos 路由
mongos --configdb configRS/localhost:27019,localhost:27020,localhost:27021 --port 27017 --logpath /var/log/mongodb/mongos.log --fork --bind_ip_all
连接 Mongos 并添加分片:
mongosh --port 27017
sh.addShard("shard1RS/localhost:27101,localhost:27102,localhost:27103")
sh.addShard("shard2RS/localhost:27201,localhost:27202,localhost:27203")
// 查看分片状态
sh.status()
六、启用分片和选择分片键
6.1 为数据库启用分片
sh.enableSharding("myapp")
6.2 分片键选择策略
分片键的选择直接影响数据分布和查询性能,是分片集群最关键的设计决策。
- 哈希分片:数据均匀分布,适合写入密集型负载。但范围查询需要广播到所有分片。
- 范围分片:支持高效的范围查询,但可能导致热点分片。
- 复合分片键:组合多个字段,兼顾分布均匀和查询效率。
6.3 配置分片集合
// 哈希分片示例(适合用户表)
sh.shardCollection("myapp.users", { user_id: "hashed" })
// 范围分片示例(适合日志表)
sh.shardCollection("myapp.logs", { created_at: 1 })
// 复合分片键示例(适合订单表)
sh.shardCollection("myapp.orders", { user_id: 1, order_date: 1 })
七、数据均衡与管理
// 查看分片分布
use myapp
db.users.getShardDistribution()
// 查看均衡器状态
sh.getBalancerState()
sh.isBalancerRunning()
// 设置均衡窗口(仅在低峰期执行迁移)
use config
db.settings.updateOne(
{ _id: "balancer" },
{ $set: { activeWindow: { start: "02:00", stop: "06:00" } } },
{ upsert: true }
)
// 手动移动 chunk
sh.moveChunk("myapp.users", { user_id: MinKey }, "shard2RS")
八、分片集群监控
// 查看集群详细状态
sh.status(true)
// 查看各分片的 chunk 数量
use config
db.chunks.aggregate([
{ $group: { _id: "$shard", count: { $sum: 1 } } }
])
// 查看慢操作
db.currentOp({ "secs_running": { $gt: 5 } })
// 查看分片键统计
db.collection.stats().shards
九、Docker Compose 部署方案
生产环境推荐使用 Docker Compose 简化部署。如果你还没安装 Docker,请参考 Docker 安装教程。以下是简化的 Compose 配置框架:
version: '3.8'
services:
config1:
image: mongo:7.0
command: mongod --configsvr --replSet configRS --port 27019
volumes:
- config1_data:/data/configdb
shard1a:
image: mongo:7.0
command: mongod --shardsvr --replSet shard1RS --port 27018
volumes:
- shard1a_data:/data/db
mongos:
image: mongo:7.0
command: mongos --configdb configRS/config1:27019,config2:27019,config3:27019 --port 27017
ports:
- "27017:27017"
depends_on:
- config1
volumes:
config1_data:
shard1a_data:
十、常见问题
- 分片键选错:分片键一旦设定不可更改(MongoDB 5.0 之前)。务必在设计阶段充分评估查询模式。
- Jumbo Chunk:单个 chunk 超过 64MB 且无法分裂,通常因为分片键值重复太多导致。
- 均衡器影响性能:chunk 迁移会消耗 IO 和网络带宽,建议设置均衡窗口在低峰期执行。
- scatter-gather 查询:查询不包含分片键时需要广播到所有分片,性能较差。确保高频查询包含分片键。
总结
MongoDB 分片集群是应对海量数据和高并发的利器,但架构复杂度也相应增加。在搬瓦工 VPS 上,如果数据量在百 GB 级以下,副本集 通常已经足够。只有当单副本集无法满足需求时再考虑分片。选购搬瓦工 VPS 请查看 全部方案,使用优惠码 NODESEEK2026 享受 6.77% 折扣,通过 bwh81.net 进入官网购买。