如何移除 MongoDB 分片 (Remove Shard)

移除MongoDB分片是一个需要谨慎执行的操作,因为它涉及数据迁移和集群重新平衡。以下是安全移除分片的完整操作流程:

准备工作

  1. 备份数据: 在进行任何重大更改前,确保有完整的数据备份
  2. 确认目标分片: 确定要移除的分片,并验证其他分片有足够容量接收迁移数据

详细操作流程

步骤1: 连接到mongos实例

bash 复制代码
mongosh "mongodb://username:password@mongos-host:27017/admin"

步骤2: 检查当前分片状态

javascript 复制代码
sh.status()

这会显示所有分片信息,包括每个分片的名称和数据分布情况。

步骤3: 停用均衡器

在移除分片之前,先停止集群的均衡器,以控制数据迁移过程:

javascript 复制代码
sh.stopBalancer()
// 确认均衡器已停止
sh.getBalancerState()  // 应返回false

步骤4: 开始分片移除过程

假设要移除的分片名为"shard2":

javascript 复制代码
db.adminCommand({ removeShard: "shard2" })

系统将返回类似以下的响应:

json 复制代码
{
   "msg" : "draining started successfully",
   "state" : "started",
   "shard" : "shard2",
   "note" : "you need to drop or move all sharded collections in that shard before completing the removal",
   "ok" : 1
}

步骤5: 监控数据迁移进度

数据迁移可能需要较长时间。可以通过以下命令检查进度:

javascript 复制代码
db.adminCommand({ removeShard: "shard2" })

在迁移过程中,系统会显示类似以下信息:

json 复制代码
{
   "msg" : "draining ongoing",
   "state" : "ongoing",
   "remaining" : {
      "chunks" : 42,
      "dbs" : 1
   },
   "ok" : 1
}

步骤6: 迁移主数据库

如果分片包含任何数据库的主副本,需要手动将这些数据库迁移到其他分片:

javascript 复制代码
// 查看哪些数据库以该分片为主分片
db.adminCommand({ listDatabases: 1, nameOnly: true }).databases.forEach(function(d) {
    if (d.name != "admin" && d.name != "config" && d.name != "local") {
        let dbInfo = db.getSiblingDB("config").databases.findOne({ _id: d.name });
        if (dbInfo.primary === "shard2") {
            print("需要迁移数据库: " + d.name);
            db.adminCommand({ movePrimary: d.name, to: "shard1" });
        }
    }
});

步骤7: 完成分片移除

当再次检查移除状态时,如果所有数据都已迁移完毕,系统会显示:

json 复制代码
{
   "msg" : "removeshard completed successfully",
   "state" : "completed",
   "shard" : "shard2",
   "ok" : 1
}

这表示分片已可以安全移除。

步骤8: 重启均衡器

完成分片移除后,重新启用均衡器:

javascript 复制代码
sh.startBalancer()
// 确认均衡器已启动
sh.getBalancerState()  // 应返回true

步骤9: 确认分片已移除

再次检查分片状态,确认目标分片已不再显示:

javascript 复制代码
sh.status()

步骤10: 停止和删除已移除分片的服务器实例

在确认分片已从集群中移除后,可以安全地停止并移除相关服务器:

bash 复制代码
# 停止mongod实例
mongod --shutdown --dbpath /path/to/shard2/data

# 或者通过进程ID关闭
kill <mongod_pid>

注意事项和最佳实践

  1. 择时操作: 选择业务低峰期进行分片移除操作

  2. 监控系统资源: 迁移过程会增加系统负载,密切监控服务器资源使用情况

  3. 设置迁移速度限制: 如果需要,可以限制迁移速度以减少对生产环境的影响

    javascript 复制代码
    db.settings.updateOne(
        { _id: "balancer" },
        { $set: { maxChunkSizeBytes: 64 * 1024 * 1024 } },  // 设置每个块最大64MB
        { upsert: true }
    )
  4. 验证数据完整性: 迁移完成后,验证数据是否完整迁移

  5. 保留日志: 保存移除操作的所有日志,以便后续排查问题

按照上述流程操作,可以安全地从MongoDB集群中移除不需要的分片,并确保数据的完整性和可用性。

附录

副本集和数据库的主分片:

正确的概念区分

  1. 副本集(Replica Set):MongoDB的一种部署架构,包含多个节点,用于数据冗余和高可用性。一个副本集中通常有一个主节点(Primary)和多个从节点(Secondary)。

  2. 主节点(Primary):副本集中负责处理所有写操作的节点,也可以处理读操作。

  3. 分片(Shard):在分片集群中,每个分片通常是一个副本集,负责存储数据的一个子集。

关于"包含任何数据库的主副本"的正确解释

在MongoDB分片集群中,每个数据库都有一个"主分片"(primary shard)的概念。这与副本集中的主节点是不同的概念:

  • 主分片(Primary Shard):指定为存储特定数据库的未分片集合的分片。每个数据库都会被指定一个主分片。

当我们说"分片包含任何数据库的主副本"时,实际指的是"该分片被指定为某个数据库的主分片(primary shard)",这意味着:

  1. 该分片存储了该数据库中所有未分片的集合
  2. 如果想移除该分片,需要先使用movePrimary命令将数据库的主分片角色迁移到另一个分片

正确的命令示例:

javascript 复制代码
db.adminCommand({ movePrimary: "databaseName", to: "destinationShardName" })
相关推荐
ai小鬼头1 小时前
Ollama+OpenWeb最新版0.42+0.3.35一键安装教程,轻松搞定AI模型部署
后端·架构·github
萧曵 丶2 小时前
Rust 所有权系统:深入浅出指南
开发语言·后端·rust
老任与码3 小时前
Spring AI Alibaba(1)——基本使用
java·人工智能·后端·springaialibaba
华子w9089258593 小时前
基于 SpringBoot+VueJS 的农产品研究报告管理系统设计与实现
vue.js·spring boot·后端
星辰离彬4 小时前
Java 与 MySQL 性能优化:Java应用中MySQL慢SQL诊断与优化实战
java·后端·sql·mysql·性能优化
GetcharZp5 小时前
彻底告别数据焦虑!这款开源神器 RustDesk,让你自建一个比向日葵、ToDesk 更安全的远程桌面
后端·rust
jack_yin6 小时前
Telegram DeepSeek Bot 管理平台 发布啦!
后端
小码编匠6 小时前
C# 上位机开发怎么学?给自动化工程师的建议
后端·c#·.net
库森学长6 小时前
面试官:发生OOM后,JVM还能运行吗?
jvm·后端·面试
转转技术团队6 小时前
二奢仓店的静默打印代理实现
java·后端