MongoDB入门学习教程,从入门到精通,MongoDB的分片管理(17)

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. 跟踪网络连接

在分片集群中,网络连接涉及mongosconfig servermongos到分片、以及分片副本集内部成员之间的连接。跟踪网络连接有助于诊断延迟、连接池耗尽或防火墙问题。

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().connectionscurrentOpconnPoolStats诊断网络瓶颈。
  • 服务器管理:实现分片的动态添加/移除、分片启用、分片键选择以及配置服务器与mongos的运维。
  • 数据均衡:控制均衡器行为,手动触发迁移,监控均衡过程,并处理常见故障。

熟练掌握这些知识点和代码案例,能够有效保障MongoDB分片集群的高可用性与性能扩展。在实际生产环境中,请结合监控报警系统(如Prometheus + Grafana)和定期巡检策略,确保集群长期稳定运行。加粗样式

相关推荐
世人万千丶2 小时前
Flutter 框架跨平台鸿蒙开发 - 嫉妒分析器应用
学习·flutter·华为·开源·harmonyos·鸿蒙
木下~learning2 小时前
MySQL 从入门到精通:安装、终端操作、远程连接与 C 语言 API 全教程
c语言·数据库·mysql
不会写DN2 小时前
如何设计应用层 ACK 来补充 TCP 的不足?
开发语言·网络·数据库·网络协议·tcp/ip·golang
升职佳兴2 小时前
告别套娃式子查询:SQL WITH 语句(CTE)深度实战指南
数据库·sql
zzh0812 小时前
PG数据库日常应用
数据库·oracle
阿维的博客日记2 小时前
MySQL中type字段解析
数据库·mysql
Trouvaille ~2 小时前
【MySQL篇】表的操作:数据的容器
linux·数据库·mysql·oracle·xshell·ddl·表的操作
黑牛儿2 小时前
从0开始实现Mysql主从配置实战
服务器·数据库·后端·mysql