MongoDB的分片管理
MongoDB分片集群通过将数据分散到多个分片上来实现水平扩展。本章将详细介绍分片集群的管理任务,包括查看集群状态、跟踪网络连接、服务器管理和数据均衡操作。所有案例均基于mongo shell(MongoDB 5.0+),并附有详细注释。
1. 查看当前状态
在分片集群中,需要定期检查分片、数据库、集合的分布状态以及各个组件的健康状况。常用命令包括sh.status()、db.printShardingStatus()以及针对配置服务器和分片节点的各种诊断命令。
1.1 查看分片集群概要
语法 :
sh.status(verbose)
verbose:可选,布尔值,默认为false。设为true时输出更详细的信息(如每个分片上的块列表)。
案例代码:
javascript
// 连接到mongos路由器(默认端口27017)
mongosh --host 127.0.0.1 --port 27017
// 查看分片集群的整体状态
sh.status()
// 输出示例:
// --- Sharding Status ---
// sharding version: { "_id" : 1, "minCompatibleVersion" : 5, ... }
// shards:
// { "_id" : "shard01", "host" : "shard01/localhost:27018", "state" : 1 }
// { "_id" : "shard02", "host" : "shard02/localhost:27019", "state" : 1 }
// active mongoses:
// "4.4.0" : 1
// autosplit:
// Currently enabled: yes
// balancer:
// Currently enabled: yes
// databases:
// { "_id" : "testDB", "primary" : "shard01", "partitioned" : true }
// 显示更详细的信息(包括每个分片上的块范围)
sh.status(true)
1.2 查看数据库和集合的分片信息
语法 :
db.getSiblingDB("数据库名").printShardingStatus()
或使用db.stats()查看分片统计。
案例代码:
javascript
// 切换到分片数据库
use myShardDB
// 查看当前数据库的分片状态
db.printShardingStatus()
// 查看指定集合的块分布情况
db.myCollection.getShardDistribution()
// 输出每个分片上该集合的数据量、文档数、占总量百分比等
// 查看分片键的索引信息
db.myCollection.getIndexes()
// 分片键必须有对应的索引(通常是哈希索引或范围索引)
1.3 检查分片节点的角色与状态
语法 :
在mongos上:sh.getBalancerState()、sh.isBalancerRunning()
在分片副本集成员上:rs.status()
案例代码:
javascript
// 在mongos上检查均衡器是否开启
sh.getBalancerState() // 返回 true/false
// 查看均衡器是否正在执行数据迁移
sh.isBalancerRunning() // 返回 true/false
// 连接到任意一个分片(如shard01的主节点)查看其副本集状态
// 先切换到分片节点:mongosh --port 27018
rs.status()
// 输出包含每个成员的 state (PRIMARY/SECONDARY/ARBITER)、健康度、延迟等信息
// 在配置服务器上查看所有分片的信息
// 连接到配置服务器:mongosh --port 27019
use config
db.shards.find().pretty()
// 输出每个分片的 _id, host, state, tags 等
2. 跟踪网络连接
在分片集群中,网络连接涉及mongos到config server、mongos到分片、以及分片副本集内部成员之间的连接。跟踪网络连接有助于诊断延迟、连接池耗尽或防火墙问题。
2.1 查看当前活跃连接
语法 :
db.serverStatus().connections
可在mongos或分片节点上执行。
案例代码:
javascript
// 在mongos上查看连接统计
use admin
db.serverStatus().connections
// 返回:
// {
// "current" : 42, // 当前打开的连接数
// "available" : 511, // 可用连接数(最大-当前)
// "totalCreated" : 1234 // 自启动以来创建的连接总数
// }
// 查看每个分片上的连接情况
// 连接到分片节点(假设端口27018)
db.serverStatus().connections
// 查看更详细的网络层统计(如网络字节流量)
db.serverStatus().network
// 返回 bytesIn, bytesOut, numRequests 等
2.2 监控当前正在进行的操作与网络延迟
语法 :
db.currentOp() -- 显示所有正在执行的操作,包括网络来源。
db.runCommand({ "ping": 1 }) -- 测试到节点的网络往返时间。
案例代码:
javascript
// 在mongos上查看所有正在进行的操作(包含客户端IP)
db.currentOp(true) // true 表示包含空闲连接和系统操作
// 关注字段:
// - "client" : "192.168.1.100:52341" 客户端地址
// - "op" : "query" / "command" / "update"
// - "ns" : "database.collection"
// - "secs_running" : 运行秒数
// - "locks" : 持有的锁信息
// 过滤出超过5秒的操作
db.currentOp({
"active": true,
"secs_running": { $gt: 5 }
})
// 测试到mongos的网络延迟
db.runCommand({ ping: 1 })
// 返回 { "ok" : 1 },实际延迟可通过客户端计时
// 测试到具体分片的延迟(先切换到分片节点)
// 使用命令行工具:mongo --host shard01 --port 27018 --eval "db.runCommand({ping:1})"
2.3 查看连接池状态(驱动层面)
MongoDB驱动内部维护连接池,但数据库端可通过connPoolStats命令查看。
语法 :
db.runCommand({ "connPoolStats": 1 })
案例代码:
javascript
// 在mongos上执行,查看连接池统计(包括到配置服务器和分片的连接)
db.runCommand({ connPoolStats: 1 })
// 输出中包含:
// - "pools" : 每个目标主机的连接池详情
// - "poolInUse" : 正在使用的连接数
// - "poolAvailable" : 空闲可用连接数
// - "created" : 已创建的连接总数
// 简化查看连接池中每个分片的连接数量
db.runCommand({ connPoolStats: 1 }).pools
3. 服务器管理
服务器管理涵盖分片集群中各种角色的服务器(配置服务器、分片副本集、mongos)的启动、停止、添加、移除和配置更改。
3.1 添加和移除分片
语法 :
sh.addShard("replicaSetName/host:port")
sh.removeShard("shardID")
案例代码:
javascript
// 连接到mongos
mongosh --port 27017
// 添加一个分片(副本集形式)
// 假设已经部署了一个名为 shard03 的副本集,包含成员 localhost:27020,27021,27022
sh.addShard("shard03/localhost:27020,localhost:27021,localhost:27022")
// 成功返回 { "ok" : 1, "added" : "shard03" }
// 添加单个mongod实例作为分片(不推荐生产环境,仅用于测试)
sh.addShard("localhost:27023")
// 查看所有分片
use config
db.shards.find()
// 移除一个分片(注意:数据需要先迁出)
sh.removeShard("shard03")
// 执行后立即返回任务状态,需要多次运行以完成数据迁移和元数据清理
// 再次运行 sh.removeShard("shard03") 查看迁移进度
3.2 启用分片并指定分片键
语法 :
sh.enableSharding("database")
sh.shardCollection("db.collection", { "key": 1 }) 或哈希分片 { "key": "hashed" }
案例代码:
javascript
// 启用数据库分片
sh.enableSharding("salesDB")
// 对集合进行范围分片(分片键为 "region" 字段)
sh.shardCollection("salesDB.orders", { "region": 1 })
// 对集合进行哈希分片(分片键为 "user_id" 字段)
sh.shardCollection("salesDB.users", { "user_id": "hashed" })
// 复合分片键(先按区域,再按日期)
sh.shardCollection("salesDB.details", { "region": 1, "date": 1 })
// 查看分片键状态
db.orders.getShardDistribution()
3.3 管理配置服务器和mongos
语法 :
配置服务器通常以副本集形式部署,管理时需修改副本集配置或重启。
mongos实例的无状态特性允许动态添加或移除。
案例代码:
javascript
// 查看配置服务器副本集状态
// 连接到任意一个配置服务器(如 localhost:27019)
rs.status()
// 确保 PRIMARY 存在且成员健康
// 动态添加一个新的 mongos 实例(无需修改其他组件)
// 只需在新机器上启动 mongos,指定相同的配置服务器字符串即可
// 示例启动命令:
// mongos --configdb cfgReplSet/localhost:27019,localhost:27020,localhost:27021 --port 27017
// 在现有 mongos 上查看已注册的其他 mongos 实例
use config
db.mongos.find().pretty()
// 输出包含每个 mongos 的 _id(通常为 host:port)和 ping 时间
// 移除一个失效的 mongos(元数据清理)
db.mongos.remove({ "_id" : "old-mongos-host:27017" })
3.4 分片节点维护(备份、重启、升级)
案例代码:
javascript
// 对分片副本集进行主节点切换(安全重启)
// 连接到分片的主节点
rs.stepDown() // 让主节点降级,触发选举新主节点
// 等待新主节点选出后,原主节点变为SECONDARY,即可安全重启
// 查看当前分片副本集的oplog窗口,确保有足够时间进行维护
rs.printReplicationInfo()
// 输出 oplog 记录的最早时间,确认不会导致复制延迟过大
// 备份分片数据(使用 mongodump,需要停止均衡器)
sh.setBalancerState(false) // 关闭均衡器
// 对每个分片执行 mongodump(建议在 SECONDARY 节点执行)
// mongodump --host secondaryHost --port 27018 --out /backup/shard01
// 完成后重新开启均衡器
sh.setBalancerState(true)
4. 数据均衡
MongoDB的均衡器(Balancer)负责自动在分片之间迁移数据块(chunk),使数据分布均匀。本部分介绍均衡器的配置、手动控制、迁移监控及常见问题处理。
4.1 均衡器的开关与调度窗口
语法 :
sh.setBalancerState(boolean) -- 全局开关
sh.enableBalancer("database.collection") -- 针对集合开启(已废弃,通常用全局)
设置均衡窗口:通过修改配置服务器的settings集合。
案例代码:
javascript
// 关闭均衡器(例如在进行大型备份或分片维护时)
sh.setBalancerState(false)
// 验证状态
sh.getBalancerState() // 返回 false
// 开启均衡器
sh.setBalancerState(true)
// 设置均衡器只在凌晨1点到6点之间运行
use config
db.settings.updateOne(
{ "_id": "balancer" },
{ $set: { "activeWindow": { "start": "01:00", "stop": "06:00" } } },
{ upsert: true }
)
// 清除时间窗口限制
db.settings.updateOne(
{ "_id": "balancer" },
{ $unset: { "activeWindow": "" } }
)
4.2 手动触发均衡与块迁移
语法 :
sh.moveChunk("db.collection", { "find": { "shardKey": value } }, "targetShard")
sh.splitAt("db.collection", { "shardKey": value }) -- 手动拆分块
案例代码:
javascript
// 手动将一个块迁移到指定分片
// 假设 salesDB.orders 的分片键为 region,将 region 为 "EU" 的块迁移到 shard02
sh.moveChunk("salesDB.orders", { "region": "EU" }, "shard02")
// 手动拆分块:将包含 region = "US" 的位置拆分为两个块
sh.splitAt("salesDB.orders", { "region": "US" })
// 拆分后原块变为 [min, "US") 和 ["US", max) 两部分
// 查看块的范围和所在分片
use config
db.chunks.find({ "ns": "salesDB.orders" }).pretty()
4.3 监控均衡过程和迁移状态
语法 :
sh.getBalancerStatus() -- 均衡器是否在运行
sh.waitForBalancer(interval, timeout) -- 等待均衡器空闲
查看迁移相关日志和config.locks集合。
案例代码:
javascript
// 查看均衡器当前是否活跃(正在迁移数据)
sh.isBalancerRunning()
// 获取均衡器详细状态(包含错误信息)
sh.getBalancerStatus()
// 等待均衡器完成当前迁移(每5秒检查一次,最多等待10分钟)
sh.waitForBalancer(5000, 600000)
// 查看正在进行的迁移任务(使用 currentOp 过滤)
db.currentOp({ "command.moveChunk": { $exists: true } })
// 或者更通用的:
db.currentOp({ "desc": "Balancer" })
// 查看分片间数据大小差异(判断是否需要均衡)
db.printShardingStatus()
// 重点关注 "data" 和 "docs" 在各个分片上的占比
// 强制均衡器立即运行(通常无需,均衡器默认持续运行)
// 方法:临时关闭再开启,并设置均衡器周期为短时间
sh.setBalancerState(false)
sh.setBalancerState(true)
// 实际均衡器会在几分钟内开始工作
4.4 配置块大小与迁移阈值
语法 :
块大小默认64MB,可通过修改config.settings调整。迁移阈值由块数量差决定。
案例代码:
javascript
// 修改块大小(单位:MB,范围1-1024,修改后自动拆分/合并)
use config
db.settings.updateOne(
{ "_id": "chunksize" },
{ $set: { "value": 128 } }, // 改为128MB
{ upsert: true }
)
// 查看当前块大小
db.settings.findOne({ "_id": "chunksize" })
// 注意:修改块大小后,现有块不会自动重新拆分,需要手动 split 或等待数据写入触发
// 迁移阈值(当分片间块数量差超过阈值时开始迁移)
// 该阈值无法直接修改,但可间接通过调整块大小和均衡窗口来控制
4.5 处理均衡失败和停机
常见问题:块迁移因文档数量过大、唯一索引约束、网络超时而失败。
案例代码:
javascript
// 查看配置服务器上的锁状态,检查是否被均衡锁卡住
use config
db.locks.find({ "_id": "balancer" }).pretty()
// 如果 "state" 为 2(等待锁),可能卡住,可手动解锁(谨慎)
// 强制释放均衡锁(仅在确认没有活跃迁移时使用)
db.locks.remove({ "_id": "balancer" })
// 迁移失败时查看错误日志(在 mongos 和分片节点日志中)
// 使用 mongod 日志级别调高来调试
db.adminCommand({ "setParameter": 1, "logLevel": 1 })
// 对于因大文档导致的迁移失败(文档超过块大小的 1/2),需要手动拆分或调整块大小
// 查找超大文档
db.orders.aggregate([
{ $match: { "region": "EU" } },
{ $group: { _id: null, avgSize: { $avg: { $bsonSize: "$$ROOT" } } } }
])
// 手动将包含超大文档的块拆分成更细粒度
sh.splitAt("salesDB.orders", { "region": "EU", "date": ISODate("2023-01-01") })
总结
本章涵盖了MongoDB分片集群管理的核心操作:
- 查看当前状态 :通过
sh.status()、db.printShardingStatus()和各组件状态命令,掌握集群健康状况。 - 跟踪网络连接 :利用
serverStatus().connections、currentOp和connPoolStats诊断网络瓶颈。 - 服务器管理:实现分片的动态添加/移除、分片启用、分片键选择以及配置服务器与mongos的运维。
- 数据均衡:控制均衡器行为,手动触发迁移,监控均衡过程,并处理常见故障。
熟练掌握这些知识点和代码案例,能够有效保障MongoDB分片集群的高可用性与性能扩展。在实际生产环境中,请结合监控报警系统(如Prometheus + Grafana)和定期巡检策略,确保集群长期稳定运行。加粗样式