MongoDB实例空间使用率高问题

更新时间:2025-03-04 08:28:48

云数据库MongoDB实例的空间使用率是一个非常重要的监控指标。如果MongoDB实例的空间被完全使用,将会导致实例不可用。本文介绍查看MongoDB实例空间使用情况的方法,以及各种空间使用情况的原因和优化策略。

背景信息

实例空间使用率达到80%以上时,可通过降低数据库实际占用空间或扩容存储空间的方法避免空间占满的风险。

查看空间使用情况

副本集架构

当云数据库MongoDB实例为副本集架构时,您可以登录MongoDB管理控制台通过以下方法查看空间使用情况:

  • 总体概览

    基本信息页面的规格信息区域,查看当前实例的磁盘空间使用率

  • 监控图分析

    在左侧导航栏中单击监控信息,选择目标节点,查看目标节点的磁盘空间使用量(Bytes)磁盘空间使用率(%)

    云数据库MongoDB副本集实例提供一个可供读写访问的Primary节点(主节点)、一个或多个提供高可用的Secondary节点(从节点)、一个隐藏的Hidden节点(隐藏节点)和一个或多个可选的ReadOnly节点(只读节点)。MongoDB节点的空间使用量由data_sizelog_size组成,即ins_size=data_size+log_size。其中:

    • data_size:数据磁盘使用空间(不包括local库),主要包括collection开头的数据物理文件、以索引开头的索引物理文件和部分元数据物理文件,例如WiredTiger.wt。

    • log_size:local库的物理大小、MongoDB运行日志大小和部分审计日志大小。

  • 详细分析

    您可以通过以下两种方法详细分析空间使用问题:

    • 通过MongoDB自身提供的命令db.stats()db.$collection_name.stats()分析。

    • CloudDBA > 空间分析页面分析。

      您可以在CloudDBA > 空间分析页面查看以下配置信息:

      • 数据库和表使用空间情况概览、日均增长量和预测可用天数。

      • 异常数据库和表使用空间情况。

      • 详细业务表使用空间情况,包括索引文件大小、数据文件大小,压缩率分析,平均行长等。

分片集群架构

当云数据库MongoDB实例为分片集群架构时,您可以登录MongoDB管理控制台通过以下方法查看空间使用情况:

  • 监控图分析

    监控信息页面,选择目标节点,查看目标节点的磁盘空间使用量(Bytes)磁盘空间使用率(%)

  • 详细分析

    通过云数据库MongoDB自身提供的命令db.stats()db.$collection_name.stats()依次分析各个节点的空间使用情况。

执行compact指令导致数据量过大

compact期间对实例的影响

由于compact执行的时间与集合的数据量相关,如果数据量过大,则会使compact的执行时间很长,所以为避免影响业务的读写,建议在业务低峰期执行compact。

compact方法

首先在备库上执行命令db.runCommand({compact:"collectionName"}),然后进行主备切换,以减少compact期间对业务的影响。其中collectionName为集合名称,请根据实际情况替换。

更多关于compact使用方法的介绍,请参见回收磁盘碎片以提升磁盘利用率

日志过大导致空间上涨

Journal Log过大导致主备空间差距巨大

云数据库MongoDB 4.0以前的版本,如果宿主机的open files达到设置上限,则会使云数据库MongoDB内部的log server清理线程中断,进而使Journal Log过大导致空间无限上涨,当通过云数据库MongoDB的运行日志查看到类似以下内容时,您可以将内核版本升级到云数据库MongoDB 4.0以上,或者通过重启云数据库mongod进程进行临时解决,详情请参见log-server thread exit quietly on error while the mongodb process still running

2019-08-25T09:45:16.867+0800 I NETWORK [thread1] Listener: accept() returns -1 Too many open files in system 
2019-08-25T09:45:17.000+0800 I - [ftdc] Assertion: 13538:couldn't open [/proc/55692/stat] Too many open files in system src/mongo/util/processinfo_linux.cpp 74
2019-08-25T09:45:17.002+0800 W FTDC [ftdc] Uncaught exception in 'Location13538: couldn't open [/proc/55692/stat] Too many open files in system' in full-time diagnostic data capture subsystem. Shutting down the full-time diagnostic data capture subsystem.

备库延迟和增量备份可能导致从节点日志空间持续增长

云数据库MongoDB在出现主备延迟的情况下,Oplog可以使用的大小不再受限于配置文件定义的固定集合大小,理论上可以达到用户申请磁盘容量的20%,但当备库延迟恢复后,Oplog之前占用的物理空间并不会回缩。

云数据库MongoDB使用物理备份的方式在隐藏节点备份云数据库MongoDB实例期间会有大量的checkpoint,进而导致占用了更多的数据和日志空间。

对于以上两种场景,通过对Oplog单独做compact操作解决,具体如下:

说明

进行compact期间会阻塞所有的写操作。

db.grantRolesToUser("root", [{db: "local", role: "dbAdmin"}])
use local
db.runCommand({ compact: "oplog.rs", force: true })

选择和使用分片不合理导致数据分布不均衡

sharding key类型选择不合理

在一个分片集群中,片键类型的选择至关重要,一般会使用hash分片或者ranged分片两种类型。通常情况下,在磁盘均衡度方面,hash分片的策略会比ranged好很多,因为根据不同的key值,云数据库MongoDB通过内部的哈希函数可以使得数据均匀地分布在不同的分片上,而range分片一般是根据key的大小范围进行数据分布,所以往往会造成这样的一个现象:新插入的数据在一个热点的chunk上,不但会引起该chunk所在的shard磁盘I/O过高,也会带来短期数据不均匀的场景。

说明

Sharding Key类型的介绍,详情请参见sharding-shard-keyhashed-shardingranged-sharding

sharding key字段选择不合理

各个分片上的chunk数量基本一致,但实际上绝大部分数据都只存储在部分chunk上,导致这些热点chunk所在的分片上的数据量远远大于其他分片上的数据量,执行命令sh.status()查看云数据库MongoDB的运行日志,从日志中可以查看到以下类似告警信息:

2019-08-27T13:31:22.076+0800 W SHARDING [conn12681919] possible low cardinality key detected in superHotItemPool.haodanku_all - key is { batch: "201908260000" } 
2019-08-27T13:31:22.076+0800 W SHARDING [conn12681919] possible low cardinality key detected in superHotItemPool.haodanku_all - key is { batch: "201908260200" } 
2019-08-27T13:31:22.076+0800 W SHARDING [conn12681919] possible low cardinality key detected in superHotItemPool.haodanku_all - key is { batch: "201908260230" }

mongos负载均衡主要考虑的是各个shardchunk数量保持相当,就认为数据是均衡的,所以就会出现以上的极端场景:虽然各个shard数量相当,但实际数据严重倾斜。因为一个chunkshardKey几乎完全相同,但触发到64MBchunk分裂阈值,这时就会分裂出一个空的chunk。久而久之,虽然chunk的数量变多了并且完成了chunk的迁移,但实际上迁移走的chunk都是空的chunk,造成了chunk数量均衡但实际数据不均衡的情况。对于这种情况,需要在架构上重新设计,选择合适的区分度较高的列作为sharding key。

说明

spilt的介绍,详情请参见sharding-data-partitioningsplit-chunks-in-sharded-cluster

部分数据库未做分片

云数据库MongoDB分片集群实例允许部分数据库做分片,部分数据库不做分片。那么必然会带来这样一个问题:不做分片的数据库的数据必然只能存在一个分片上,如果该数据库的数据量很大,可能会造成该分片的数据量远大于其他分片。

从一个源端mongos集群导入到一个新的mongos集群,但逻辑导入过程中忽略了在目标端mongos集群做好分片设计的步骤。

针对上述问题,我们建议:

  • 如果是因为目标集群初始化导入,导入之前做好分片设计。

  • 如果不做分片的库很多且数据量基本相当,通过云数据库MongoDB提供的命令movePrimary将指定数据库迁移到指定分片。

  • 如果存在某个数据库的数据量极大且未做分片,建议对其做分片设计或者将其拆分出来作为单一的副本集对待。

  • 如果出现这种情况,但磁盘空间足够大,建议忽略该问题。

大规模的movechunk操作可能引起分片的磁盘占用不均

movechunk的本质是向目标端shard写入数据后remove源端数据。默认情况下,remove操作不会释放空间,因为对于wiredTiger引擎,每个表都有独立的数据文件和索引文件,如果该文件不删除,总的磁盘空间就不可能回缩。通常最容易引起该问题的操作为:之前的sharding集群中未做shard设计,运行一段时间后才做了Sharding。

从原理上说movechunk引起的空间碎片和大规模删除一样,因此针对出现大量movechunk或者remove文档的情况,可以对该分片进行compact操作来回收碎片空间,正常情况下compact后数据会进行重组以回收文件的碎片空间。

说明

  • 本页导读 (1)
  • 背景信息
  • 查看空间使用情况
  • 副本集架构
  • 分片集群架构
  • 执行compact指令导致数据量过大
  • compact期间对实例的影响
  • compact方法
  • 日志过大导致空间上涨
  • Journal Log过大导致主备空间差距巨大
  • 备库延迟和增量备份可能导致从节点日志空间持续增长
  • 选择和使用分片不合理导致数据分布不均衡
  • sharding key类型选择不合理
  • sharding key字段选择不合理
  • 部分数据库未做分片
  • 大规模的movechunk操作可能引起分片的磁盘占用不均