云数据库MongoDB实例在使用过程中,删除数据并不会回收磁盘空间,这些未被回收的磁盘空间被称为磁盘碎片。频繁删除数据或删除大量数据后,会产生很多磁盘碎片。本文介绍如何回收磁盘碎片以提升磁盘利用率。

前提条件

实例的存储引擎为WiredTiger。

背景信息

执行db.runCommand({collStats: <collection_name>}) 命令访问节点时,返回结果有两个关键字:sizestorageSize。其中,size表示集合的逻辑存储大小,storageSize表示集合的物理存储大小。在执行remove命令删除文档后,size的值会减少,但是,storageSize的值不一定会减少。通过比较sizestorageSize的大小,可以判断是否产生磁盘碎片。
说明
  • 云数据库MongoDB 4.4及以上版本,还可以通过返回结果的freeStorageSize关键字查看磁盘碎片中空闲并可以被回收的磁盘空间。
  • 关于sizestorageSizefreeStorageSize关键字的更多信息,请参见collStats-Output

compact是云数据库MongoDB的压缩命令,执行compact命令可以回收删除数据后产生的磁盘碎片,实现压缩磁盘空间的目的,从而提升磁盘利用率。关于compact命令的更多信息,请参见compact

当磁盘碎片率不高时,执行compact命令会因为云数据库MongoDB实例的WiredTiger存储引擎限制,达不到预期效果,因此,不建议频繁执行compact命令。

当集合的数据量比较小时,您可以将数据拷贝到一个新集合,再执行db.collection.drop()命令删除旧集合,从而提升磁盘利用率。执行db.collection.drop()命令删除集合时,集合中的文件会被全部删除,并且磁盘空间会被回收。

注意事项

  • 回收磁盘碎片前,建议对数据库进行备份,如何备份,请参见手动备份MongoDB数据
  • 回收磁盘碎片会导致集合所属的数据库被锁定,且该数据库的读写操作将被阻塞,建议您在业务低峰期操作。
    说明 执行compact命令回收磁盘碎片所需的时间与集合数据量、系统负载等因素有关。

预估回收的磁盘碎片空间

  1. 通过MongoDB Shell连接云数据库MongoDB实例。不同类型实例的连接方法如下:
  2. 将数据库切换至集合所在的数据库。
    语法:
    use <database_name>
    参数说明:<database_name>为集合所在的数据库名称。
    说明 您可以通过show dbs命令查询现有的数据库。

    示例:

    切换至test_database数据库。
    use test_database
  3. 查看集合需回收的磁盘碎片空间。
    语法:
    db.<collection_name>.stats().wiredTiger["block-manager"]["file bytes available for reuse"]
    参数说明:<collection_name>为集合名称。
    说明 您可以通过show tables命令查询现有的集合。
    示例:
    db.test_database_collection.stats().wiredTiger["block-manager"]["file bytes available for reuse"]
    返回结果如下:
    207806464

    该返回结果表示预估回收的磁盘碎片空间为207806464 Byte。

回收单节点或副本集实例的磁盘碎片

  • 单节点实例只有一个StandAlone节点,您只需要连接主节点(Primary节点),执行compact命令回收主节点(Primary节点)的磁盘碎片。
  • 副本集实例具有多个节点,您需要分别连接主节点(Primary节点)和从节点(Secondary节点),在不同节点上执行compact命令回收相应节点的磁盘碎片,执行的回收命令相同。
    说明 如果副本集实例具有只读节点(Readonly节点),您还需要回收只读节点(Readonly节点)的磁盘碎片,执行的回收命令与回收主从节点磁盘碎片的命令相同。
  1. 通过Mongo Shell连接单节点或副本集实例。不同类型实例的连接方法如下:
  2. 将数据库切换至集合所在的数据库。
    语法:
    use <database_name>
    参数说明:<database_name>为集合所在的数据库名称。
    说明 您可以通过show dbs命令查询现有的数据库。

    示例:

    切换至replica_database数据库。
    use replica_database
  3. 查看回收磁盘碎片前数据库占用的磁盘空间。
    db.stats()
    说明 该命令可以直接复制执行,无需修改。
  4. 回收集合的磁盘碎片。
    语法:
    db.runCommand({compact:"<collection_name>",force:true})
    参数说明:
    • <collection_name>:集合名称。
      说明 您可以通过show tables命令查询现有的集合。
    • force:可选项,取值固定为true

      如果您在4.2及以下版本的云数据库MongoDB实例主节点(Primary节点)上执行该命令,该参数为必填项。

    示例:

    db.runCommand({compact:"sharded_collection"})
    执行成功的返回结果如下:
    { "ok" : 1 }
  5. 查看回收磁盘碎片后数据库占用的磁盘空间。
    db.stats()
    说明 该命令可以直接复制执行,无需修改。

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

分片集群实例只需要回收Shard组件中对应节点的磁盘碎片。Mongos组件和ConfigServer组件均不存储用户数据,并且增加和更新操作偏多,删除操作偏少,不需要回收磁盘碎片。
说明 分片集群实例的只读节点不支持compact命令,所以无法回收只读节点(ReadOnly节点)的磁盘碎片。
  1. 通过Mongo Shell连接分片集群实例,如何连接,请参见通过Mongo Shell连接MongoDB分片集群实例
  2. 将数据库切换至集合所在的数据库。
    语法:
    use <database_name>
    参数说明:<database_name>为集合所在的数据库名称。
    说明 您可以通过show dbs命令查询现有的数据库。

    示例:

    切换至sharded_database数据库。
    use sharded_database
  3. 查看回收磁盘碎片前数据库占用的磁盘空间。
    db.stats()
    说明 该命令可以直接复制执行,无需修改。
  4. 回收集合的磁盘碎片。

    您需要分别回收Shard组件中主节点(Primary节点)和从节点(Secondary节点)的磁盘碎片。

    • 回收Shard组件中主节点(Primary节点)的磁盘碎片。
      语法:
      db.runCommand({runCommandOnShard:"<Shard ID>","command":{compact:"<collection_name>",force:true}})
      参数说明:
      • <Shard ID>:Shard组件的ID。
        说明 您可以登录MongoDB管理控制台,在目标实例基本信息页面的Shard列表区域查看Shard组件的ID。
      • <collection_name>:集合名称。
        说明 您可以通过show tables命令查询现有的集合。
      • force:可选项,取值固定为true

        如果您的分片集群实例版本为4.2及以下版本,该参数为必填项。

      示例:
      db.runCommand({runCommandOnShard:"shard01","command":{compact:"sharded_collection",force:true}})
    • 回收Shard组件中从节点(Secondary节点)的磁盘碎片。
      语法:
      db.runCommand({runCommandOnShard:"<Shard ID>","command":{compact:"<collection_name>"},$queryOptions: {$readPreference: {mode: 'secondary'}}})
      参数说明:
      • <Shard ID>:Shard组件的ID。
        说明 您可以登录MongoDB管理控制台,在目标实例基本信息页面的Shard列表区域查看Shard组件的ID。
      • <collection_name>:集合名称。
        说明 您可以通过show tables命令查询现有的集合。
      • force:可选项,取值固定为true
      示例:
      db.runCommand({runCommandOnShard:"shard01","command":{compact:"sharded_collection"},$queryOptions: {$readPreference: {mode: 'secondary'}}})
  5. 查看回收磁盘碎片后数据库占用的磁盘空间。
    db.stats()
    说明 该命令可以直接复制执行,无需修改。