回收磁盘碎片以提升磁盘利用率
本文介绍云数据库MongoDB实例如何回收磁盘碎片以提升磁盘利用率。
在删除云数据库MongoDB实例的数据后,这些被删除数据使用的存储空间会被标记为空闲,随后写入的新数据可能会被直接存储到这部分空闲的存储空间中,也可能会先扩展文件的存储空间再存储到文件末尾。上述情况将导致一部分空闲的存储空间不会被使用,这些未被使用的空闲存储空间被称之为磁盘碎片,磁盘碎片越多,磁盘利用率就越低。
前提条件
实例的存储引擎为WiredTiger。
背景信息
执行db.runCommand({collStats: <collection_name>})
命令访问节点时,返回结果有两个关键字:size
和storageSize
。其中,size
表示集合的逻辑存储大小,storageSize
表示集合的物理存储大小。在执行remove
命令删除文档后,size
的值会减少,但是,storageSize
的值不一定会减少。当storageSize
大于size
时,表示已产生磁盘碎片。
云数据库MongoDB 4.4及以上版本,还可以通过返回结果的
freeStorageSize
关键字查看磁盘碎片中空闲并可以被回收的磁盘空间。关于
size
、storageSize
和freeStorageSize
关键字的更多信息,请参见collStats-Output。
compact
是云数据库MongoDB的压缩命令,执行compact
命令可以回收删除数据后产生的磁盘碎片,实现压缩磁盘空间的目的,从而提升磁盘利用率。关于compact
命令的更多信息,请参见compact。
注意事项
回收磁盘碎片前,建议对数据库数据进行备份,备份方法,请参见手动备份MongoDB数据。
MongoDB 4.4及之前的版本执行
compact
命令会导致集合所属的数据库被锁定,且该数据库的读写操作将被阻塞,建议您在业务低峰期操作。受阻塞的具体介绍,请参见MongoDB官网文档。说明执行
compact
命令回收磁盘碎片所需的时间与集合数据量、系统负载等因素有关。以下场景可能会导致compact命令执行无效,更多介绍请参见开源代码。
物理集合大小小于1 MB。
文件前80%的存储空间中,空闲存储空间小于20%;文件前90%的存储空间中,空闲存储空间小于10%。
执行compact命令时,可能会出现释放的存储空间小于空闲的存储空间的情况。如果出现上述情况,您可以重复执行compact命令来释放磁盘碎片,但不建议您频繁执行compact命令。
compact命令可以在磁盘空间满导致实例锁定的情况下执行。
预估回收的磁盘碎片空间
通过MongoDB Shell连接云数据库MongoDB实例。不同类型实例的连接方法如下:
将数据库切换至集合所在的数据库。
语法:
use <database_name>
参数说明:
<database_name>
为集合所在的数据库名称。说明您可以通过
show dbs
命令查询现有的数据库。示例:
切换至test_database数据库。
use test_database
查看集合需回收的磁盘碎片空间。
语法:
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节点)的磁盘碎片,执行的回收命令与回收主从节点磁盘碎片的命令相同。
通过Mongo Shell连接单节点或副本集实例。不同类型实例的连接方法如下:
将数据库切换至集合所在的数据库。
语法:
use <database_name>
参数说明:
<database_name>
为集合所在的数据库名称。说明您可以通过
show dbs
命令查询现有的数据库。示例:
切换至replica_database数据库。
use replica_database
查看回收磁盘碎片前数据库占用的磁盘空间。
db.stats()
说明该命令可以直接复制执行,无需修改。
回收集合的磁盘碎片。
语法:
db.runCommand({compact:"<collection_name>",force:true})
参数说明:
<collection_name>
:集合名称。说明您可以通过
show tables
命令查询现有的集合。force
:可选项,取值固定为true。如果您在4.2及以下版本的云数据库MongoDB实例主节点(Primary节点)上执行该命令,该参数为必填项。
示例:
db.runCommand({compact:"sharded_collection"})
执行成功的返回结果如下:
{ "ok" : 1 }
查看回收磁盘碎片后数据库占用的磁盘空间。
db.stats()
说明该命令可以直接复制执行,无需修改。
回收分片集群实例的磁盘碎片
分片集群实例只需要回收Shard组件中对应节点的磁盘碎片。Mongos组件和ConfigServer组件均不存储用户数据,并且增加和更新操作偏多,删除操作偏少,不需要回收磁盘碎片。
分片集群实例的只读节点不支持compact
命令,所以无法回收只读节点(ReadOnly节点)的磁盘碎片。
通过Mongo Shell连接分片集群实例,如何连接,请参见通过Mongo Shell连接MongoDB分片集群实例。
将数据库切换至集合所在的数据库。
语法:
use <database_name>
参数说明:
<database_name>
为集合所在的数据库名称。说明您可以通过
show dbs
命令查询现有的数据库。示例:
切换至sharded_database数据库。
use sharded_database
查看回收磁盘碎片前数据库占用的磁盘空间。
db.stats()
说明该命令可以直接复制执行,无需修改。
回收集合的磁盘碎片。
您需要分别回收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
命令查询现有的集合。
示例:
db.runCommand({runCommandOnShard:"shard01","command":{compact:"sharded_collection"},$queryOptions: {$readPreference: {mode: 'secondary'}}})
查看回收磁盘碎片后数据库占用的磁盘空间。
db.stats()
说明该命令可以直接复制执行,无需修改。