MongoDB-3 分片集群
MongoDB 分片集群(Sharded Cluster)详解
- MongoDB 分片集群是一种水平扩展的数据库架构,用于处理海量数据和高吞吐量应用。它将数据分布在多个服务器上,使系统能够超越单台服务器的存储和性能限制。
1. 分片集群的核心组件
分片(Shard)
- 功能:存储实际数据块(chunks)
- 组成:每个分片可以是一个独立的 MongoDB 实例,但生产环境推荐使用副本集
- 特点:
- 每个分片存储部分数据
- 可以动态添加更多分片来扩展容量
配置服务器(Config Servers)
- 功能:存储集群的元数据和配置信息
- 要求:
- 必须部署为副本集(至少3个节点)
- 存储分片键范围、数据块位置等元数据
查询路由器(Mongos)
-
功能:作为应用程序的入口点。提供客户端应用程序和分片集群之间的接口
-
特点:
- 不存储数据
- 将查询路由到正确的分片
- 可以部署多个实例以提高可用性
-
生产环境中,常见的分片集群架构
![image]()
-
测试环境中,常见的分片集群架构
![image]()
2. 分片集群工作原理
2.1 数据分布机制
- 数据根据分片键(Shard Key)被分成多个数据块(chunks)。shard key由文档中的一个或多个字段组成
- 每个chunk默认大小为64MB(可配置)
- 当chunk达到大小阈值时,会自动分裂
- 平衡器(Balancer)会在分片间迁移chunk以保持数据块在集群所有分片上实现均匀分布
2.2 查询路由流程
- 应用连接mongos发起查询
- mongos检查查询是否包含分片键
- 包含分片键:定向到特定分片(定向查询)
- 不包含分片键:广播到所有分片(分散-聚集查询)
- mongos合并结果并返回给客户端
3. 分片策略
3.1 分片键选择
-
哈希分片:
- 对分片键值计算哈希
- 优点:数据分布均匀
- 缺点:不支持范围查询
-
范围分片:
- 基于分片键的值范围
- 优点:支持高效范围查询
- 缺点:可能导致数据分布不均
4. 部署分片集群
架构
- config server(配置服务器)、shard(分片)均以副本集形式构建,每个服务器上部署三个分片,每个服务器上部署一个mongos(路由器)
![image]()
4.1 部署config server副本集
修改配置文件
- 不同节点修改IP即可
cat <<EOF> /etc/mongod-config.conf
storage:
dbPath: /apps/mongodb/config-data-27020
# engine:
# wiredTiger:
systemLog:
destination: file
logAppend: true
path: /apps/mongodb/config-logs-27020/config.log
net:
port: 27020
bindIp: 192.168.40.31
processManagement:
fork: true
pidFilePath: /apps/mongodb/config-27020.pid
timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
replication:
replSetName: configserver
sharding:
clusterRole: configsvr
EOF
创建目录
mkdir -p /apps/mongodb/config-{data,logs}-27020
启动config server 服务
# 在三台主机上分别启动config server
mongod --config /etc/mongod-config.conf
将config server配置成副本集
- 连接config server,被连接的节点将成为主节点
mongosh --host mongo01:27020
- 初始化config server
rs.initiate(
{
_id : "configserver",
members: [
{ _id : 0, host : "mongo01:27020" },
{ _id : 1, host : "mongo02:27020" },
{ _id : 2, host : "mongo03:27020" }
]
}
)
4.2 部署shard副本集
配置hosts文件
cat <<EOF>> /etc/hosts
192.168.40.31 mongo01
192.168.40.32 mongo02
192.168.40.33 mongo03
EOF
修改配置文件
- shard1的副本集名称是rs1,端口号27017,主节点是mongo01
- shard2的副本集名称是rs2,端口号27018,主节点是mongo02
- shard3的副本集名称是rs3,端口号27019,主节点是mongo03
- shard1、shard2、shard3的bindIp修改为对应主机的IP
shard1主节点的配置文件
cat <<EOF> /etc/mongod-shard1.conf
storage:
dbPath: /apps/mongodb/shard1-data-27017
# engine:
# wiredTiger:
systemLog:
destination: file
logAppend: true
path: /apps/mongodb/shard1-logs-27017/shard1.log
net:
port: 27017
bindIp: 192.168.40.31
processManagement:
fork: true
pidFilePath: /apps/mongodb/shard1-27017.pid
timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
replication:
replSetName: rs1
sharding:
clusterRole: shardsvr
EOF
shard2主节点的配置文件
cat <<EOF> /etc/mongod-shard2.conf
storage:
dbPath: /apps/mongodb/shard2-data-27018
# engine:
# wiredTiger:
systemLog:
destination: file
logAppend: true
path: /apps/mongodb/shard2-logs-27018/shard2.log
net:
port: 27018
bindIp: 192.168.40.32
processManagement:
fork: true
pidFilePath: /apps/mongodb/shard2-27018.pid
timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
replication:
replSetName: rs2
sharding:
clusterRole: shardsvr
EOF
shard3主节点的配置文件
cat <<EOF> /etc/mongod-shard3.conf
storage:
dbPath: /apps/mongodb/shard3-data-27019
# engine:
# wiredTiger:
systemLog:
destination: file
logAppend: true
path: /apps/mongodb/shard3-logs-27019/shard3.log
net:
port: 27019
bindIp: 192.168.40.33
processManagement:
fork: true
pidFilePath: /apps/mongodb/shard3-27019.pid
timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
replication:
replSetName: rs3
sharding:
clusterRole: shardsvr
EOF
创建目录
mkdir -p /apps/mongodb/shard1-{data,logs}-27017 # mongo01
mkdir -p /apps/mongodb/shard2-{data,logs}-27018 # mongo02
mkdir -p /apps/mongodb/shard3-{data,logs}-27019 # mongo03
启动shard服务
# 在三个节点上分别启动shard1、shard2、shard3
mongod --config /etc/mongod-shard1.conf
mongod --config /etc/mongod-shard2.conf
mongod --config /etc/mongod-shard3.conf
配置副本集
- shard1
mongosh --host mongo01:27017
rs.initiate(
{
_id : "rs1",
members: [
{ _id : 0, host : "mongo01:27017" },
{ _id : 1, host : "mongo02:27017" },
{ _id : 2, host : "mongo03:27017" }
]
}
)
- shard2
mongosh --host mongo02:27018
rs.initiate(
{
_id : "rs2",
members: [
{ _id : 0, host : "mongo01:27018" },
{ _id : 1, host : "mongo02:27018" },
{ _id : 2, host : "mongo03:27018" }
]
}
)
- shard3
mongosh --host mongo03:27019
rs.initiate(
{
_id : "rs3",
members: [
{ _id : 0, host : "mongo01:27019" },
{ _id : 1, host : "mongo02:27019" },
{ _id : 2, host : "mongo03:27019" }
]
}
)
4.3 部署mongos路由器
修改配置文件
- 三台主机分别修改bindIp
cat <<EOF> /etc/mongod-mongos.conf
systemLog:
destination: file
logAppend: true
path: /apps/mongodb/mongos-logs-27021/mongos.log
net:
port: 27021
bindIp: 192.168.40.31
processManagement:
fork: true
pidFilePath: /apps/mongodb/mongos-27021.pid
timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
sharding:
configDB: configserver/mongo01:27020,mongo02:27020,mongo03:27020
EOF
创建目录
# 三台主机分别创建目录
mkdir -p /apps/mongodb/mongos-logs-27021
启动mongos
# 三台主机分别启动mongos
mongos --config /etc/mongod-mongos.conf
4.4 向分片集群中添加分片
- 添加分片只需连接任意一个mongos,只需添加一次,即可同步到mongos集群的其他节点
# 连接到mongos
mongosh --host mongo01:27021
# 添加分片
sh.addShard("rs1/mongo01:27017,mongo02:27017,mongo03:27017")
sh.addShard("rs2/mongo01:27018,mongo02:27018,mongo03:27018")
sh.addShard("rs3/mongo01:27019,mongo02:27019,mongo03:27019")
启用数据库分片
- 启用分片后,可以在Navicat中连接mongos查看到对应的数据库和集合
// 启用数据库分片
sh.enableSharding("mydatabase")
// 对集合进行分片
sh.shardCollection("mydatabase.mycollection", { "shardKey": 1 })
5. 分片集群管理
5.1 监控集群状态
javascript
// 查看分片状态
sh.status()
// 查看平衡器状态
sh.getBalancerState()
// 查看数据分布
db.mycollection.getShardDistribution()
5.2 添加新分片
javascript
sh.addShard("shardReplSet2/shard2a.example.net:27018,shard2b.example.net:27018,shard2c.example.net:27018")
5.3 平衡器管理
javascript
// 停止平衡器
sh.stopBalancer()
// 启动平衡器
sh.startBalancer()
// 设置平衡窗口
use config
db.settings.update(
{ _id: "balancer" },
{ $set: { activeWindow: { start: "23:00", stop: "6:00" } } },
{ upsert: true }
)
6. 分片集群最佳实践
6.1 分片键选择原则
基数高(大量不同值)
写分布均匀
匹配查询模式
避免单调递增的分片键(如时间戳、自增ID)
6.2 性能优化
为分片键创建索引
监控热点分片
合理设置chunk大小(默认64MB)
使用预分割(pre-splitting)避免初始写入热点
6.3 容量规划
每个分片应保留30%的可用空间
监控磁盘使用情况
提前规划分片扩展
- 常见问题与解决方案
7.1 分片键无法修改
问题:一旦选择分片键就无法更改
解决方案:
创建新集合并设置新分片键
将数据从旧集合迁移到新集合
更新应用使用新集合
7.2 数据分布不均
问题:某些分片负载过高
解决方案:
重新评估分片键选择
使用哈希分片代替范围分片
手动迁移热点chunk
7.3 跨分片查询性能
问题:无分片键查询性能差
解决方案:
尽可能在查询中包含分片键
为常用查询创建复合索引
考虑使用$or替代分散-聚集查询
启动脚本
cat <<EOF> start-mongo-cluster.sh
#!/bin/bash
mongod --config /etc/mongod-config.conf
sleep 5
mongod --config /etc/mongod-shard1.conf
sleep 5
mongod --config /etc/mongod-shard2.conf
sleep 5
mongod --config /etc/mongod-shard3.conf
sleep 5
mongos --config /etc/mongos.conf
EOF
关闭脚本
cat <<EOF> stop-mongo-cluster.sh
#!/bin/bash
mongo_home=/apps/mongodb
declare -A pid_map
pid_map["mongos"]=$(cat ${mongo_home}/mongos*.pid 2>/dev/null | tr '\n' ' ' | xargs)
pid_map["shard"]=$(cat ${mongo_home}/shard*.pid 2>/dev/null | tr '\n' ' ' | xargs)
pid_map["config"]=$(cat ${mongo_home}/config*.pid 2>/dev/null | tr '\n' ' ' | xargs)
for component in mongos shard config; do
pid=${pid_map[$component]}
if [ -z "$pid" ]; then
continue # 无PID直接跳过,不输出任何提示
fi
echo "正在关闭 $component(PID:$pid)"
kill -15 $pid >/dev/null 2>&1
sleep 15
case $component in
mongos)
ps_out=$(ps -ef | grep mongos | grep -v grep | wc -l)
;;
shard)
ps_out=$(ps -ef | grep mongod | grep shard | grep -v grep | wc -l)
;;
config)
ps_out=$(ps -ef | grep mongod | grep config | grep -v grep | wc -l)
;;
esac
if [ $ps_out -eq 0 ]; then
echo "$component 已成功关闭"
fi
done
EOF




浙公网安备 33010602011771号