MongoDB分片架构与NoSQL选型场景
MongoDB分片(Sharding)是水平扩展的核心机制,通过将数据分散到多个Shard节点实现存储容量和吞吐量的线性扩展。在NoSQL选型应用场景中,当单台MongoDB实例的数据量超过内存容量或写入吞吐达到磁盘I/O瓶颈时,分片集群是必经之路。与MySQL分库分表方案相比,MongoDB分片对应用层透明,客户端通过mongos路由自动定位数据位置。
MongoDB分片集群由三个组件构成:Config Server(配置服务器,存储集群元数据和分片路由信息)、Mongos(路由服务,接收客户端请求并转发到目标Shard)、Shard(数据分片,每个Shard是一个副本集)。数据库高可用架构要求每个Shard至少3节点副本集(1 Primary + 2 Secondary),保证单节点故障时数据不丢失。
分片集群部署架构规划
以3分片集群为例,共需要13个MongoDB实例:
– Config Server: 3节点副本集(csrs)
– Shard1: 3节点副本集
– Shard2: 3节点副本集
– Shard3: 3节点副本集
– Mongos: 1个路由实例
# 端口规划
# Config Server: 27019, 27020, 27021
# Shard1: 27001, 27002, 27003
# Shard2: 27004, 27005, 27006
# Shard3: 27007, 27008, 27009
# Mongos: 27017
# 创建数据目录
mkdir -p /data/mongodb/{config1,config2,config3}
mkdir -p /data/mongodb/{shard1-1,shard1-2,shard1-3}
mkdir -p /data/mongodb/{shard2-1,shard2-2,shard2-3}
mkdir -p /data/mongodb/{shard3-1,shard3-2,shard3-3}
Config Server副本集搭建
Config Server存储分片集群的路由表和Chunk分布信息,必须以副本集方式部署以保证高可用。
# 启动3个Config Server实例
mongod --configsvr --replSet csrs --dbpath /data/mongodb/config1 --port 27019 --fork --logpath /var/log/mongodb/config1.log
mongod --configsvr --replSet csrs --dbpath /data/mongodb/config2 --port 27020 --fork --logpath /var/log/mongodb/config2.log
mongod --configsvr --replSet csrs --dbpath /data/mongodb/config3 --port 27021 --fork --logpath /var/log/mongodb/config3.log
# 初始化Config Server副本集
mongo --port 27019 << 'EOF'
rs.initiate({
_id: "csrs",
configsvr: true,
members: [
{ _id: 0, host: "192.168.1.10:27019" },
{ _id: 1, host: "192.168.1.10:27020" },
{ _id: 2, host: "192.168.1.10:27021" }
]
})
EOF
# 验证状态
mongo --port 27019 --eval "rs.status()"
Shard副本集搭建与集群添加
每个Shard以副本集方式部署,保证数据冗余和自动故障转移。
# 启动Shard1的3个实例
mongod --shardsvr --replSet shard1 --dbpath /data/mongodb/shard1-1 --port 27001 --fork --logpath /var/log/mongodb/shard1-1.log
mongod --shardsvr --replSet shard1 --dbpath /data/mongodb/shard1-2 --port 27002 --fork --logpath /var/log/mongodb/shard1-2.log
mongod --shardsvr --replSet shard1 --dbpath /data/mongodb/shard1-3 --port 27003 --fork --logpath /var/log/mongodb/shard1-3.log
# 初始化Shard1副本集
mongo --port 27001 << 'EOF'
rs.initiate({
_id: "shard1",
members: [
{ _id: 0, host: "192.168.1.10:27001", priority: 2 },
{ _id: 1, host: "192.168.1.10:27002", priority: 1 },
{ _id: 2, host: "192.168.1.10:27003", priority: 1 }
]
})
EOF
# 同理启动并初始化Shard2和Shard3
# Shard2: 端口27004-27006, replSet shard2
# Shard3: 端口27007-27009, replSet shard3
# 启动Mongos路由
mongos --configdb csrs/192.168.1.10:27019,192.168.1.10:27020,192.168.1.10:27021 --port 27017 --fork --logpath /var/log/mongodb/mongos.log
# 连接Mongos并添加Shard
mongo --port 27017 << 'EOF'
sh.addShard("shard1/192.168.1.10:27001,192.168.1.10:27002,192.168.1.10:27003")
sh.addShard("shard2/192.168.1.10:27004,192.168.1.10:27005,192.168.1.10:27006")
sh.addShard("shard3/192.168.1.10:27007,192.168.1.10:27008,192.168.1.10:27009")
# 查看集群状态
sh.status()
EOF
分片键选择与集合分片配置
分片键(Shard Key)决定了数据在Shard间的分布方式,是分片集群最重要的配置。选择不当会导致数据分布不均(jumbo chunk)或查询性能下降。
# 连接Mongos启用数据库分片
mongo --port 27017 << 'EOF'
# 启用数据库分片
sh.enableSharding("ecommerce")
# 创建分片键索引(必须先创建索引)
db.orders.createIndex({ "user_id": 1, "created_at": 1 })
# 对集合启用分片,使用复合分片键
sh.shardCollection("ecommerce.orders", { "user_id": 1, "created_at": 1 })
# 使用哈希分片(适合数据分布不均匀的字段)
db.events.createIndex({ "event_id": "hashed" })
sh.shardCollection("ecommerce.events", { "event_id": "hashed" })
# 查看分片分布
db.orders.getShardDistribution()
# 查看Chunk分布
sh.status({ verbose: true })
EOF
分片键策略对比:
范围分片(Ranged Sharding):按分片键值范围划分Chunk,适合范围查询。但容易出现热点——递增ID的写入集中在最后一个Shard。
哈希分片(Hashed Sharding):对分片键计算哈希值后分布数据,写入均匀分散到所有Shard。但不支持范围查询优化。
区域分片(Zone Sharding):将特定范围的数据固定到特定Shard,如按地理区域分片,实现数据本地化。
Balancer与Chunk迁移管理
Balancer是MongoDB分片集群的自动均衡组件,当Shard间Chunk数量差异超过阈值时自动触发Chunk迁移。数据库运维场景下需监控Balancer状态并控制迁移窗口。
# 查看Balancer状态
sh.getBalancerState()
# 查看Balancer窗口配置
sh.getBalancerWindow()
# 设置Balancer运行窗口(仅在低峰期运行)
mongo --port 27017 << 'EOF'
db.settings.update(
{ _id: "balancer" },
{ $set: { activeWindow: { start: "02:00", stop: "06:00" } } },
{ upsert: true }
)
# 手动触发Balancer
sh.startBalancer()
# 查看迁移状态
sh.isBalancerRunning()
# 设置迁移参数
db.settings.update(
{ _id: "balancer" },
{ $set: {
"chunkMigrationConcurrency": 2,
"maxChunkSizeBytes": 128 * 1024 * 1024
}},
{ upsert: true }
)
EOF
分片集群故障排查与数据备份
数据备份恢复在分片集群环境中更为复杂,需要使用mongodump备份每个Shard或使用文件系统快照。
# 方式1:通过Mongos备份(适合小数据量)
mongodump --host 192.168.1.10 --port 27017 --db ecommerce --out /backup/mongodb/$(date +%Y%m%d)
# 方式2:备份每个Shard(适合大数据量,需停止Balancer)
mongo --port 27017 --eval "sh.stopBalancer()"
for port in 27001 27004 27007; do
mongodump --host 192.168.1.10 --port $port --out /backup/mongodb/shard_$port
done
mongo --port 27017 --eval "sh.startBalancer()"
# 监控关键指标
# Chunk数量分布
db.getSiblingDB("config").chunks.aggregate([
{ $group: { _id: "$shard", count: { $sum: 1 } } }
])
# 检查jumbo chunk
db.getSiblingDB("config").chunks.find({ jumbo: true })
# 副本集健康状态
for shard in shard1 shard2 shard3; do
echo "=== $shard ==="
mongo --eval "rs.status().members.filter(m => m.stateStr === 'PRIMARY' || m.stateStr === 'SECONDARY')"
done
数据库运维实践中,分片集群的数据迁移操作应避开业务高峰期。监控Chunk迁移速率和锁等待时间,防止迁移任务消耗过多I/O资源影响在线业务。对于高频写入场景,建议将分片键选择为写入路径上的自然维度字段,避免跨Shard事务。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/mongodb-fen-pian-ji-qun-da-jian-shi-zhan-shard-fen-pian-yu/