You need to enable JavaScript to run this app.
导航
通过 COMPACT 命令回收 MongoDB 实例磁盘碎片
最近更新时间:2025.02.08 18:20:39首次发布时间:2023.09.18 15:16:10

本文介绍如何通过 compact 命令回收 MongoDB 实例的磁盘碎片,减少磁盘使用压力,提高利用率。

背景信息

文档数据库 MongoDB 版实例在删除数据时,不会直接回收被删除数据的磁盘空间(这些空间会被标记为空闲),后续新写入的数据不会占用新的磁盘空间,而是重用之前空闲的磁盘空间,那些未被使用的空闲存储空间则被称作磁盘碎片。随着删除的操作增多,碎片也会越来越多,磁盘碎片越多表明磁盘利用率越低。
Compact 命令可用于重写和整理 MongoDB 集合中所有的数据和索引,通过回收数据删除后所产生的磁盘碎片来提升磁盘利用率。关于 compact 命令的更多信息,请参见 compact

前提条件

文档数据库 MongoDB 版支持副本集和分片集群两种架构的实例,实例类型不同,执行 compact 命令回收磁盘空间时的前提条件不同:

  • 副本集实例
    已分别获取实例的主节点(Primary node)、从节点(Secondary node)、隐藏节点(Hidden node)的单节点连接地址。
    您可以登录 MongoDB 控制台后,在目标副本集实例连接管理页签下的单节点地址表格中查看各节点的连接地址。具体操作步骤,请参见查看连接地址
    alt
  • 分片集群实例
    • 已为目标 shard 分片申请私网连接地址。具体操作步骤,请参见申请私网地址

      说明

      文档数据库 MongoDB 版分片集群实例只需回收 Shard 组件中对应节点的磁盘碎片。Mongos 和 ConfigServer 组件均不存储业务数据,并且增加和更新操作偏多,删除操作偏少,一般不需要回收磁盘碎片。关于分片集群实例各组件的更多信息,请参见分片集群

    • 已分别获取 shard 分片中主节点、从节点和隐藏节点的单节点连接地址。
      您可以登录 MongoDB 控制台后,在目标分片集群实例连接管理页签下的连接Shard 区域,单击目标 shard 右侧的图标,在展开的表格中查看各节点的连接地址。具体操作步骤,请参见查看连接地址
      alt

注意事项

  • 建议在回收磁盘碎片前,先对数据库数据进行备份。数据备份的具体方法,请参见手动备份
  • 集合数据量、系统负载等因素会影响回收磁盘碎片的执行时间。
  • 您可以在回收磁盘碎片前,先通过 Mongo shell 连接 MongoDB 实例并进入目标数据库,使用 collStats 命令查看数据库所占用的磁盘空间详情,便于在回收结束后确认磁盘碎片回收效果。具体操作步骤,请参见预估可回收的磁盘碎片空间
  • 针对 MongoDB 4.4 及之前版本的实例,在隐藏节点(Hidden node)上执行 compact 命令会导致集合所属的数据库被锁定,且会阻塞数据库的读写操作。建议您在业务低峰期,严格按照本文操作顺序进行磁盘碎片回收操作,减少对业务的影响。关于受阻塞命令的更多详情,请参见 Blocking。若您在回收磁盘空间操作过程中遇到问题,请提交工单联系技术支持。
  • 如需终止当前 compact 命令操作,您可以新建一个连接后,通过 db.killOp(opid) 命令来终止正在运行中的 compact 操作。关于 db.killOp() 命令的更多详情,请参见 db.killOp()

预估可回收的磁盘碎片空间

  1. 通过 Mongo Shell 连接文档数据库 MongoDB 版实例。具体操作步骤,请参见通过 Mongo Shell 工具连接实例

    说明

    对于 MongoDB 副本集实例,为降低业务影响,建议您连接副本集实例的从节点(Secondary node)操作。

  2. 执行 use <数据库名称> 命令进入目标数据库。
    示例如下。

    use test_db
    

    说明

    您可以通过 show dbs 命令查询当前 MongoDB 实例中的已有的数据库。

  3. 通过 collStats 命令查看目标集合的存储空间状况。

    db.runCommand({collStats:"<集合名称>"})
    

    说明

    您可以通过 show tables 命令查询现有当前数据库中已有的集合。

    示例如下。

    db.runCommand({collStats:"test_db_col"})
    

    在返回结果中,需要重点关注如下信息:

    说明

    • 通过 delete 命令删除文档后,size 的值会减少,但 storageSize 的值不一定会减少。您可以观察 freeStorageSizestorageSize 中的占比,占比率较高时,代表磁盘碎片率较高。
    • 文档数据库 MongoDB 4.4 及以上版本才支持查看 freeStorageSize 字段。更多关于 collStats 命令的信息,请参见 collStats

回收副本集实例的磁盘碎片

步骤一:回收隐藏节点上的磁盘碎片

  1. 在安装了 Mongo Shell 的本地服务器或 ECS 中,在如下命令的对应位置输入副本集实例的数据库账号、密码,以及隐藏节点(Hidden node)的单节点连接地址来连接隐藏节点。
    mongo "mongodb://<数据库账号>:<账号密码>@<前提条件中已获取的隐藏节点(Hidden node)的单节点连接地址>/?authSource=admin"
    
    示例如下。
    mongo "mongodb://root:Pwd_123@mongoreplica****2.mongodb.ivolces.com:3717/?authSource=admin"
    
  2. 执行 rs.isMaster() 命令确认当前连接的节点是否为隐藏节点。
    命令示例如下。
    rs-mongo-replica-****:SECONDARY|test rs.isMaster()
    
    返回结果示例如下。

    说明

    如下示例中仅展示了部分字段。返回结果中 hidden 字段值为 true,即表明当前连接的是隐藏节点。

    {
            "hosts" : [
                    'mongoreplica****0.mongodb.ivolces.com:3717',
                    'mongoreplica****1.mongodb.ivolces.com:3717'
            ],
            "setName" : "rs-mongo-replica-****",
            "setVersion" : 12444,
            "ismaster" : false,
            "secondary" : true,
            "primary" : "mongoreplica****0.mongodb.ivolces.com:3717",
            "passive" : true,
            "hidden" : true,  
             ....... 
    }
    
  3. 执行如下 compact 命令回收磁盘碎片。
    db.runCommand({compact:"<collection_name>"})
    
    本文以 test_collect 为例,命令示例如下。
    db.runCommand({compact:"test_collect"})
    
    若返回结果中出现 "ok" : 1 ,即表示 compact 命令执行成功。

步骤二:回收从节点上的磁盘碎片

  1. 在安装了 Mongo Shell 的本地服务器或 ECS 中,在如下命令的对应位置输入副本集实例的数据库账号、密码,以及从节点(Secondary node)的单节点连接地址来连接从节点。
    mongo "mongodb://<数据库账号>:<账号密码>@<前提条件中已获取的从节点(Secondary node)的单节点连接地址>/?authSource=admin"
    
    示例如下。
    mongo "mongodb://root:Pwd_123@mongoreplica****1.mongodb.ivolces.com:3717/?authSource=admin"
    
    1. 执行 rs.isMaster() 命令确认当前连接的节点是否为从节点。
      命令示例如下。
    rs-mongo-replica-****:SECONDARY|test rs.isMaster()
    
    返回结果示例如下。

    说明

    如下示例中仅展示了部分字段。返回结果中 secondary 字段值为 true,即表明当前连接的是从节点。

    {
            "hosts" : [
                    'mongoreplica****0.mongodb.ivolces.com:3717',
                    'mongoreplica****1.mongodb.ivolces.com:3717'
            ],
            "setName" : "rs-mongo-replica-****",
            "setVersion" : 12444,
            "ismaster" : false,
            "secondary" : true,
            "primary" : "mongoreplica****0.mongodb.ivolces.com:3717",
            .......
    }
    
  2. 执行 compact 命令回收磁盘碎片。

    说明

    在从节点中执行 compact 命令的方法和在隐藏节点上的一样。具体的命令详情和示例,请参见回收隐藏节点上的磁盘碎片

步骤三:手动切换主节点

手动将已完成磁盘碎片回收的从节点切换为主节点,详细操作步骤,请参见切换主节点

说明

  • 手动切换主节点过程(一般需要 30~60 秒)中,实例可能会出现 1~2 次连接闪断,请谨慎操作。建议在业务低峰期执行切换操作,并确保应用具备自动重连机制。
  • 手动切换主节点仅改变节点的角色,不会改变节点所在的可用区和节点 ID。

步骤四:回收新从节点上的磁盘碎片

主节点切换成功后,参考回收从节点上磁盘碎片的相关步骤,连接到切换后的新从节点并完成磁盘碎片回收。具体操作步骤,请参见回收从节点上的磁盘碎片

说明

所有节点上的磁盘碎片回收完成后,您可以再次通过 Mongo shell 连接 MongoDB 实例并进入目标数据库,使用 collStats 命令查看数据库所占用的磁盘空间详情,便于在回收结束后确认磁盘碎片回收效果。具体操作步骤,请参见预估可回收的磁盘碎片空间

回收分片集群实例的磁盘碎片

说明

MongoDB 分片集群实例只需要回收 Shard 组件中对应节点的磁盘碎片。Mongos 组件和 ConfigServer 组件均不存储业务数据,且这两个组件记录的增加和更新操作偏多,删除操作偏少,因此不需要回收磁盘碎片。

步骤一:回收 shard 上隐藏节点的磁盘碎片

  1. 在安装了 Mongo Shell 的本地服务器或 ECS 中,在如下命令的对应位置输入分片集群实例的数据库账号、密码,以及目标 shard 中隐藏节点(Hidden node)的单节点连接地址来连接隐藏节点。
    mongo "mongodb://<数据库账号>:<账号密码>@<前提条件中已获取的隐藏节点(Hidden node)的单节点连接地址>/?authSource=admin"
    
    示例如下。
    mongo "mongodb://root:Pwd_123@mongoshard****s02.mongodb.ivolces.com:3717/?authSource=admin"
    
  2. 执行 rs.isMaster() 命令确认当前连接的节点是否为隐藏节点。
    命令示例如下。
    rs-mongo-shard-****-s0:SECONDARY|test> rs.isMaster()
    
    返回结果示例如下。

    说明

    如下示例中仅展示了部分字段。返回结果中 hidden 字段值为 true,即表明当前连接的是 隐藏节点。

    {
            "hosts" : [
                    "mongoshard****s00.ivolces.com:3717",
                    "mongoshard****s01.ivolces.com:3717"
            ],
            "setName" : "rs-mongo-shard-****-s0",
            "setVersion" : 12444,
            "ismaster" : false,
            "secondary" : true,
            "primary" : "mongoshard****s00.ivolces.com:3717",
            "passive" : true,
            "hidden" : true,  
             ....... 
    }
    
  3. 执行如下 compact 命令回收磁盘碎片。
    db.runCommand({compact:"<collection_name>"})
    
    本文以 test_collect 为例,命令示例如下。
    db.runCommand({compact:"test_collect"})
    
    若返回结果中出现 "ok" : 1 ,即表示 compact 命令执行成功。

步骤二:回收 shard 上从节点的磁盘碎片

  1. 在安装了 Mongo Shell 的本地服务器或 ECS 中,在如下命令的对应位置输入分片集群实例的数据库账号、密码,以及目标 shard 中从节点(Secondary node)的单节点连接地址来连接从节点。
    mongo "mongodb://<数据库账号>:<账号密码>@<前提条件中已获取的从节点(Secondary node)的单节点连接地址>/?authSource=admin"
    
    示例如下。
    mongo "mongodb://root:Pwd_123@mongoshard****s01.mongodb.ivolces.com:3717/?authSource=admin"
    
  2. 执行 rs.isMaster() 命令确认当前连接的节点是否为从节点。
    命令示例如下。
    rs-mongo-shard-****-s0:SECONDARY|test> rs.isMaster()
    
    返回结果示例如下。

    说明

    如下示例中仅展示了部分字段。返回结果中 secondary 字段值为 true,即表明当前连接的是从节点。

    {
            "hosts" : [
                    "mongoshard****s00.ivolces.com:3717",
                    "mongoshard****s01.ivolces.com:3717"
            ],
            "setName" : "rs-mongo-shard-****-s0",
            "setVersion" : 12444,
            "ismaster" : false,
            "secondary" : true,
            "primary" : "mongoshard****s00.ivolces.com:3717",
            .......
    }
    
  3. 执行 compact 命令回收磁盘碎片。

    说明

    在从节点中执行 compact 命令的方法和在隐藏节点上的一样。具体的命令详情和示例,请参见回收 shard 上隐藏节点的磁盘碎片

步骤三:手动切换主节点

手动将已完成磁盘碎片回收的从节点切换为主节点,详细操作步骤,请参见切换主节点

注意

  • 手动切换主节点过程(一般需要 30~60 秒)中,实例可能会出现 1~2 次连接闪断,请谨慎操作。建议在业务低峰期执行切换操作,并确保应用具备自动重连机制。
  • 手动切换主节点仅改变节点的角色,不会改变节点所在的可用区和节点 ID。

步骤四:回收 shard 上新从节点上的磁盘碎片

主节点切换成功后,参考回收从节点上的磁盘碎片相关步骤,连接到切换后的新从节点并完成磁盘碎片回收。具体操作步骤,请参见回收 shard 上从节点的磁盘碎片

说明

所有节点上的磁盘碎片回收完成后,您可以再次通过 Mongo Shell 连接 MongoDB 分片集群实例并进入目标数据库,使用 db.stats() 命令查看数据库所占用的磁盘空间详情,与回收前的磁盘空间数据进行对比,确认磁盘碎片回收效果。具体操作步骤,请参见预估可回收的磁盘碎片空间