如何移除 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" })
相关推荐
终身学习基地17 分钟前
第一篇:Django简介
后端·python·django
Apifox2 小时前
Apifox 4月更新|Apifox在线文档支持LLMs.txt、评论支持使用@提及成员、支持为团队配置「IP 允许访问名单」
前端·后端·ai编程
我家领养了个白胖胖2 小时前
#和$符号使用场景 注意事项
java·后端·mybatis
寻月隐君2 小时前
如何高效学习一门技术:从知到行的飞轮效应
后端·github
Andya2 小时前
Java | 深拷贝与浅拷贝工具类解析和自定义实现
后端
Andya2 小时前
Java | 基于自定义注解与AOP切面实现数据权限管控的思路和实践
后端
云原生melo荣2 小时前
快速记忆Spring Bean的生命周期
后端·spring
阿里云腾讯云谷歌云AWS代理商_小赵2 小时前
腾讯云国际站:为什么Docker适合部署在云服务器?
后端
Java中文社群2 小时前
大模型向量数据库去重的N种实现方案!
java·人工智能·后端
小奏技术2 小时前
字节最新开源项目CompoundVM-在JDK8上启用JVM17
后端