有奖捉虫:行业应用 & 管理与支持文档专题 HOT
文档中心 > 云数据库 MongoDB > 最佳实践 > 性能调优 > 磁盘空间利用率偏高解决方法

操作场景

MongoDB 的磁盘主要存储数据和索引,以及一些系统文件和日志文件。磁盘空间利用率是一个非常重要的监控指标,当磁盘空间被完全使用时,MongoDB 实例将无法继续写入新的数据,这将导致实例出现故障并停止工作。因此,监控磁盘利用率并及时采取措施来释放磁盘空间,是确保 MongoDB 实例正常运行的关键。

查看磁盘空间使用情况

快速查看监控指标

登录 MongoDB 控制台,在系统监控页签,可查看磁盘空间利用率的变化趋势视图。具体操作,请参见 查看监控数据




详细分析磁盘空间使用情况

登录 MongoDB 控制台,在左侧导航栏,选择诊断优化,再选择空间分析页签。可通过数据库智能管家(TencentDB for DBbrain,DBbrain)的空间分析功能,进一步分析数据库的磁盘空间的使用详情,包括数据库的集合空间、索引空间、物理文件空间大小,以及数据库大小、数据占比、集合的行数等分析数据及视图等。具体操作,请参见 空间分析



通过 MongoDB 自身提供的命令db.stats()db.$collection_name.stats()分析磁盘空间使用情况。具体信息,请参见下表。
分析命令
命令含义
该命令用于获取当前数据库的统计信息。执行db.stats()命令将返回一个文档,其中包含有关当前数据库的各种信息,如:数据库名称、数据大小、索引大小、集合数量等。
该命令用于获取指定集合的统计信息。执行db.collection.stats()命令将返回一个文档,其中包含有关指定集合的各种信息,如:集合名称、文档数量、数据大小、索引数量等。
该命令用于获取指定集合占用的存储空间大小。执行db.collection.storageSize()命令将返回指定集合的存储空间大小,单位为字节。该命令所返回的存储空间大小包括集合中的数据和索引等占用的空间,但不包括 MongoDB 实例的其他开销,如日志文件和临时文件等。
该命令用于获取指定集合的所有索引占用的存储空间大小。执行db.collection.totalIndexSize()命令将返回指定集合的所有索引占用的存储空间大小,单位为字节。该命令所返回的存储空间大小不包括集合中的数据占用的空间,只包括集合的所有索引占用的空间。
该命令用于获取指定集合占用的总存储空间大小。执行db.collection.totalSize()命令将返回指定集合占用的总存储空间大小,单位为字节。该命令所返回的存储空间大小包括集合中的数据和索引等占用的空间,以及 MongoDB 实例的其他开销,如日志文件和临时文件等。

问题分析

云数据库 MongoDB 默认使用的是 WiredTiger 引擎,删除文档时,并不会直接回收磁盘空间。当插入新的数据时,MongoDB 会重用之前占用的空间,而不会继续额外占用新的磁盘空间。随着删除的操作增多,碎片也会越来越多。如下代码,可一次性查看指定数据库的所有 collection 碎片率。
当实例磁盘空间利用率达到80%~85%以上时,可通过降低数据库实际占用空间或扩容存储空间的方法避免空间占满的风险。
##生成查看碎片率的函数
function getCollectionDiskSpaceFragRatio(dbname, coll) { var res = db.getSiblingDB(dbname).runCommand({ collStats: coll }); var totalStorageUnusedSize = 0; var totalStorageSize = res['storageSize'] + res['totalIndexSize']; Object.keys(res.indexDetails).forEach(function(key) { var size = res['indexDetails'][key]['block-manager']['file bytes available for reuse']; print("index table " + key + " unused size: " + size); totalStorageUnusedSize += size; }); var size = res['wiredTiger']['block-manager']['file bytes available for reuse']; print("collection table " + coll + " unused size: " + size); totalStorageUnusedSize += size; print("collection and index table total unused size: " + totalStorageUnusedSize); print("collection and index table total file size: " + totalStorageSize); print("Fragmentation ratio: " + ((totalStorageUnusedSize * 100.0) / totalStorageSize).toFixed(2) + "%"); }
##指定数据库,查看所有集合的碎片率 use xxxdb db.getCollectionNames().forEach((c) => {print("\\n\\n" + c); getCollectionDiskSpaceFragRatio(db.getName(), c);});

解决方法

磁盘使用率高且碎片率高

云数据库 MongoDB 为 4.4及以上版本
若磁盘使用率高(一般80%~85%以上),碎片率较高(一般超过25%以上,才有做回收的收益),云数据库 MongoDB 为 4.4及以上版本副本集架构,请使用命令db.runCommand({compact:"collectionName"})对指定的集合文档进行压缩来释放磁盘空间。其中,collectionName为集合名称,请根据实际情况替换。
说明:
当 MongoDB 执行 Compact 操作时,会对整个数据库进行压缩。因此在此期间,集合的创建和删除、索引的创建和删除等操作会被阻塞,而其他操作(如查询)则不会受到影响,但是存在负载影响,请求会有时延。建议在业务低峰期执行该操作。
云数据库 MongoDB 为4.4之前版本
若磁盘使用率高(一般80%~85%以上),碎片率较高(一般超过25%以上,才有做回收的收益),云数据库 MongoDB 为 4.4以下版本,不建议操作campact,会阻塞实例的所有请求,可能会出现 Compact 索引无效的问题,解决方案如下:
升级版本,建议升级到最新版本以获得更好的性能和稳定性。具体操作,请参见 版本升级
如果不想升级版本,可以通过逻辑迁移来重建节点达到收缩空间的效果,操作过程中会存在多次闪断。具体操作,请联系售后或 提交工单

磁盘使用率高但碎片率不高

若磁盘使用率高(一般80%~85%以上),而碎片率并不高,碎片率低于20%,不建议进行campact操作,因为 MongoDB 会复用这部分空间。此时请扩容磁盘空间,具体操作,请参见 变更 Mongod 节点配置规格