MongoDB分片集群是解决大规模数据水平扩展的核心架构。通过Shard分片机制,将数据按片键分布到多个节点,实现存储容量和查询吞吐量的线性扩展。本文从分片集群架构设计、Config Server配置、Mongos路由部署到片键选型,给出MongoDB分片集群的完整搭建方案。
MongoDB分片集群架构组成
MongoDB分片集群由三个核心组件构成:
- Shard(分片节点):存储实际数据,每个分片是一个独立的mongod实例或副本集。生产环境必须使用副本集部署,保证单分片高可用。
- Config Server(配置服务器):存储集群元数据,包括分片信息、块范围和数据库分片策略。必须以副本集方式部署,官方建议至少3个节点。
- Mongos(路由节点):接收客户端请求,根据Config Server的元数据将请求路由到对应的分片。是无状态节点,可以水平扩展。
典型的生产环境拓扑:3个Config Server(副本集)+ N个Shard(每个为副本集)+ 2-3个Mongos。
Config Server副本集部署
Config Server以副本集方式运行,3个节点保证元数据的高可用。以下是三节点配置服务器部署配置:
# config-server-1.conf
sharding:
clusterRole: configsvr
net:
port: 27019
bindIp: 0.0.0.0
replication:
replSetName: cfgReplSet
storage:
dbPath: /data/configdb
journal:
enabled: true
systemLog:
destination: file
path: /var/log/mongodb/config-server.log
logAppend: true
security:
authorization: enabled
keyFile: /data/keyfile/mongodb-keyfile
三个节点的配置文件相同,仅dbPath和日志路径不同。启动后初始化副本集:
# 连接到第一个配置节点
mongosh --port 27019
# 初始化副本集
rs.initiate({
_id: "cfgReplSet",
configsvr: true,
members: [
{ _id: 0, host: "192.168.1.10:27019" },
{ _id: 1, host: "192.168.1.11:27019" },
{ _id: 2, host: "192.168.1.12:27019" }
]
})
# 查看副本集状态
rs.status()
Shard分片副本集部署
每个Shard必须以副本集方式运行。以两个分片为例,每个分片3个节点:
# shard-1-node1.conf
sharding:
clusterRole: shardsvr
net:
port: 27018
bindIp: 0.0.0.0
replication:
replSetName: shardReplSet1
storage:
dbPath: /data/shard1
journal:
enabled: true
security:
authorization: enabled
keyFile: /data/keyfile/mongodb-keyfile
初始化分片1副本集:
mongosh --port 27018
rs.initiate({
_id: "shardReplSet1",
members: [
{ _id: 0, host: "192.168.1.20:27018" },
{ _id: 1, host: "192.168.1.21:27018" },
{ _id: 2, host: "192.168.1.22:27018" }
]
})
分片2副本集配置类似,replSetName改为shardReplSet2,端口改为27028。
Mongos路由节点部署
Mongos是客户端接入点,从Config Server获取集群元数据,将请求路由到对应分片:
# mongos.conf
sharding:
configDB: cfgReplSet/192.168.1.10:27019,192.168.1.11:27019,192.168.1.12:27019
net:
port: 27017
bindIp: 0.0.0.0
security:
keyFile: /data/keyfile/mongodb-keyfile
systemLog:
destination: file
path: /var/log/mongodb/mongos.log
logAppend: true
# 启动mongos
mongod --config /etc/mongod/mongos.conf
# 连接mongos,添加分片到集群
mongosh --port 27017
# 添加分片
sh.addShard("shardReplSet1/192.168.1.20:27018,192.168.1.21:27018,192.168.1.22:27018")
sh.addShard("shardReplSet2/192.168.1.30:27028,192.168.1.31:27028,192.168.1.32:27028")
# 查看集群状态
sh.status()
片键选型与分片策略配置
片键(Shard Key)决定数据在分片间的分布方式,是分片集群设计中最重要的决策。片键一旦设定不可修改(MongoDB 4.4+支持通过reshardingCollection变更片键,但成本较高)。
范围分片(Range-based):按片键值范围划分数据,适合范围查询场景。但容易出现热点,大量写入同一范围的请求会集中到单个分片。
# 启用数据库分片
sh.enableSharding("ecommerce")
# 对集合创建片键索引
db.users.createIndex({ userId: 1 })
# 按userId范围分片
sh.shardCollection("ecommerce.users", { userId: 1 })
哈希分片(Hash-based):对片键计算哈希值后分布数据,写入均匀分布到所有分片,适合高写入吞吐场景。但不支持范围查询。
# 创建哈希索引
db.logs.createIndex({ logId: "hashed" })
# 按logId哈希分片
sh.shardCollection("ecommerce.logs", { logId: "hashed" })
复合片键:多个字段组合作为片键,兼顾范围查询和写入分布。推荐格式:{ coarse_field: 1, fine_field: 1 },coarse字段基数低(如地区),fine字段基数高(如时间戳)。
sh.shardCollection("ecommerce.orders", { region: 1, orderTime: 1 })
分片集群数据均衡配置
MongoDB内置Balancer进程,自动迁移块(Chunk)以均衡各分片数据量。可以手动控制均衡行为:
# 查看均衡器状态
sh.getBalancerState()
# 临时停止均衡器(维护窗口)
sh.stopBalancer()
# 设置均衡窗口:仅在凌晨2-6点运行
db.settings.update(
{ _id: "balancer" },
{ $set: { activeWindow: { start: "02:00", stop: "06:00" } } },
{ upsert: true }
)
# 查看各分片数据分布
db.getSiblingDB("config").chunks.aggregate([
{ $group: { _id: "$shard", count: { $sum: 1 } } }
])
# 手动迁移块
sh.moveChunk("ecommerce.users", { userId: 5000 }, "shardReplSet2")
分片集群查询路由机制
Mongos根据查询条件是否包含片键,采用不同的查询路由策略:
定向查询(Targeted Query):查询条件包含片键,Mongos直接将请求路由到对应分片,性能最优。
// 包含片键userId,定向到单个分片
db.users.find({ userId: 10001 })
广播查询(Broadcast Query):查询条件不包含片键,Mongos将请求发送到所有分片,合并结果返回。大量广播查询会显著增加集群负载。
// 不含片键,广播到所有分片
db.users.find({ email: "test@example.com" })
通过explain()查看查询路由信息:
db.users.find({ userId: 10001 }).explain("executionStats")
// 查看executionStats.shardStage确认是否为定向查询
分片集群运维与监控
生产环境需要持续监控分片集群状态,关键监控指标包括:
// 查看集群整体状态
sh.status()
// 查看各分片存储大小
db.getSiblingDB("config").shards.find()
// 查看数据库分片状态
db.getSiblingDB("config").databases.find()
// 查看块迁移状态
db.getSiblingDB("config").migrations.find()
// 查看连接数
db.serverStatus().connections
// 查看各分片操作统计
db.serverStatus().opcounters
当某个分片数据量或负载明显偏高时,需要检查片键选择是否合理。如果热点集中在某个片键范围,可以通过增加分片数量或调整片键解决。
分片集群常见问题排查
数据分布不均匀:检查片键基数。如果片键基数过低(如只有几十个不同值),大量数据会集中在少数块上。建议片键基数至少与分片数量比例为1000:1以上。
块迁移导致性能下降:调整均衡窗口到低峰时段运行。通过chunkSize参数控制块大小(默认64MB),较小的块迁移更快但元数据开销更大。
查询性能差:确认查询是否使用了片键。对常用查询字段创建索引,确保覆盖索引包含片键字段。使用hint()强制指定索引。
添加新分片后数据不均衡:新分片加入后,Balancer会自动迁移数据。迁移速度取决于网络带宽和磁盘IO,大集群可能需要数小时达到均衡。可以通过降低chunkSize加速迁移。
Mongos连接异常:Mongos是无状态节点,重启不影响数据。但重启后需要从Config Server重新加载元数据,高并发下可能短暂返回错误。生产环境建议部署多个Mongos,通过负载均衡器分发请求。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/mongodb-fen-pian-ji-qun-bu-shu-shi-zhan-shard-fen-pian-yu/