如何移除 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" })
相关推荐
Apifox17 小时前
Apifox CLI + Claude Skills:将接口自动化测试融入研发工作流
前端·后端·测试
调试人生的显微镜17 小时前
使用Fiddler抓包工具获取微信公众号数据的完整教程
后端
货拉拉技术17 小时前
性能突破:星图平台架构优化
后端
UIUV17 小时前
Git 提交规范与全栈AI驱动开发实战:从基础到高级应用
前端·javascript·后端
程序员清风18 小时前
猿辅导二面:线上出现的OOM是如何排查的?
java·后端·面试
DCTANT18 小时前
【原创】使用更优雅的方式改造MyBatisPlus逻辑删除插件
spring boot·后端·mysql·kotlin·mybatis·mybatisplus
上进小菜猪18 小时前
基于 YOLOv8 的太阳能电池片缺陷智能检测识别实战 [目标检测完整源码]
后端
Rysxt_18 小时前
Go语言:现代编程的效率与并发之选
开发语言·后端·golang
Mr -老鬼19 小时前
Rust 知识图-谱基础部分
开发语言·后端·rust
袁慎建@ThoughtWorks19 小时前
如何发布自定义 Spring Boot Starter
java·spring boot·后端