跳到主要内容

回收磁盘空间

在删除 MongoDB 实例中的数据后,这些被删除数据使用的存储空间会被标记为空闲,随后相同集合写入的新数据通常会被直接存储到这部分空闲的存储空间中。但无法被其他集合复用这部分空闲存储空间,这些未被使用的空闲存储空间被称之为磁盘碎片,磁盘碎片越多,磁盘利用率就越低。

回收磁盘空间有两种方法:使用 compact 命令和重建数据文件。

  • compact 命令:这是集合级别的操作,需要逐个集合进行压缩处理。

  • 重建数据文件:这是数据库实例级别的操作,针对整个数据库执行,通常更全面。

compact

注意事项

  • 操作之前,请务必先对数据库数据进行完整备份。

  • MongoDB 4.4之前的版本执行 compact 命令会导致集合所属的数据库被锁定,且该数据库的读写操作将被阻塞,建议您在业务低峰期或升级版本后操作。受阻塞的具体介绍,请参见 MongoDB 官方文档

    • 执行 compact 命令回收磁盘碎片所需的时间与集合数据量、系统负载、磁盘性能等因素有关,执行期间也会对CPU、内存占用也有一定增长。

    • 小于 4.4.9 的版本,正在执行 compact 命令的节点会强制进入 RECOVERING 状态,如果持续时间过长,该节点会被将无法继续同步 PRIMARY 节点数据。

    • 4.4.9 - 4.4.17 之间的 MongoDB 版本,执行 compact 命令的节点则会保持在 SECONDARY 状态,但是依旧运行中状态依旧无法同步 PRIMARY 节点数据。

    • 4.4.17 之后的版本在执行 compactSECONDARY 节点会持续复制 PRIMARY 节点数据。(建议在大于 4.4.17 的版本下操作 compact

  • 以下场景可能会导致 compact 命令执行无效,更多介绍请参见开源代码

    • 物理集合大小小于 1 MB。

    • 文件前 80% 的存储空间中,空闲存储空间小于 20%;文件前 90% 的存储空间中,空闲存储空间小于 10%。

  • 执行 compact 命令时,可能会出现释放的存储空间小于空闲的存储空间的情况。如果出现上述情况,您可以尝试重复执行 compact 命令来释放磁盘碎片,但不建议您频繁执行 compact 命令。

预估回收的磁盘碎片空间

  1. 将数据库切换至集合所在的数据库。

    use database_name
    • database_name 为集合所在的数据库名称。
  2. 查看集合需回收的磁盘碎片空间。

    db.collection_name.stats().wiredTiger["block-manager"]["file bytes available for reuse"]
    • collection_name 为集合名称。

    返回结果如下:

    1485426688

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

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

单节点

单节点实例只有一个节点,所以只需针对这个实例点执行 compact 命令即可。

副本集

副本集实例具有多个节点,执行顺序:

  1. 在其中一个 SECONDARY 节点执行 compactcompact 完成后,依次在每个剩余的 SECONDARY 节点上重复此操作。

  2. 重新分配主节点,在 PRIMARY 节点,使用 rs.stepDown() 方法触发重新选举 PRIMARY 节点。当 PRIMARY 节点转变为 SECONDARY 状态并成功选举出新 PRIMARY 节点后,即可执行 compact 命令。

    • 如果需要在 PRIMARY 节点强制执行 compact 命令,则需要添加 foce 参数,例如:

      db.runCommand({compact:"collection_name",force:true})

compact 操作方法

  1. 通过 Mongo Shell 连接数据库节点。

  2. 将数据库切换至集合所在的数据库。

    use database_name
    • database_name 为集合所在的数据库名称。
  3. 指定集合执行 compact,回收集合的磁盘碎片。

    db.runCommand({compact:"collection_name"})
    • collection_name 为集合名称。

    执行成功的返回结果如下:

    { "ok" : 1 }

重建数据文件

注意事项

  • 操作之前,请务必先对数据库数据进行完整备份。

  • 重建数据文件所需的时间与集合数据量、系统负载、磁盘性能等因素有关。

单节点

  1. 停止应用服务

  2. 停止 MongoDB 数据库

  3. 使用 mongod--repair 参数来重建数据文件,从而回收磁盘空间。

    示例:

    mongod --repair --dbpath /data/mongodb/
    • /data/mongodb/ 为 MongoDB 数据存储目录

    • 执行期间请勿中断操作,否则可能会影响数据完整性,导致数据库无法启动。

  4. 启动 MongoDB 数据库

副本集

通过删除 SECONDARY 节点上的数据,并利用 MongoDB 副本集的内部重新同步机制,可以重建数据文件,从而回收磁盘空间。

  1. 在任意一个 SECONDARY 节点上执行以下命令,删除当前节点数据(排除 keyfile 文件)

    find /data/mongodb/ -mindepth 1 ! -name 'keyfile' -exec rm -rf {} +
    • 该命令排除 /data/mongodb/ 目录下的 keyfile 文件,删除其他所有文件和子目录。
  2. 重启当前 MongoDB 节点

  3. 使用 rs.status() 命令检查节点状态。在同步过程中,节点状态会显示为 STARTUP2,同步完成后会变为 SECONDARY

  4. 当上一个节点完成同步并且节点状态变为 SECONDARY 后,可以在剩余的 SECONDARY 节点上依次重复该操作。

  5. 最后,在 PRIMARY 节点上使用 rs.stepDown() 方法触发重新选举。当 PRIMARY 节点转变为 SECONDARY 状态并成功选举出新 PRIMARY 节点后,可以对该节点执行上述相同操作。