【巡检问题分析与最佳实践】MongoDB 空间使用问题

本文涉及的产品
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
云数据库 Tair(兼容Redis),内存型 2GB
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 阿里云数据库MongoDB的空间使用率是一个非常重要的监控指标,如果实例的存储空间完全打满,将会直接导致实例不可用。一般来说,当一个MongoDB实例的存储空间使用比例达到80-85%以上时,就应及时进行处理,要么降低数据库实际占用空间的大小,要么对存储空间进行扩容,以避免空间打满的风险。然而,阿里云数据库MongoDB的空间使用情况分析并不简单,本文将由浅入深帮您查看,分析和优化云数据库MongoDB的空间使用。

往期分享

RDS MySQL

RDS MySQL 实例空间问题

RDS MySQL 内存使用问题

RDS MySQL 活跃线程数高问题

RDS MySQL 慢SQL问题

RDS MySQL 实例IO高问题

RDS MySQL 小版本升级最佳实践

RDS PostgreSQL

RDS PostgreSQL 实例IO高问题

RDS PostgreSQL 慢SQL问题

RDS PostgreSQL CPU高问题

RDS SQL Server

RDS SQL Server 磁盘IO吞吐高问题

RDS SQL Server CPU高问题

RDS SQL Server 空间使用问题

Redis

Redis 流控问题

Redis 内存高问题

Redis CPU高问题

MongoDB

MongoDB 内存高问题

MongoDB 磁盘IO高问题

概述

阿里云数据库MongoDB的空间使用率是一个非常重要的监控指标,如果实例的存储空间完全打满,将会直接导致实例不可用。一般来说,当一个MongoDB实例的存储空间使用比例达到80-85%以上时,就应及时进行处理,要么降低数据库实际占用空间的大小,要么对存储空间进行扩容,以避免空间打满的风险。

然而,阿里云数据库MongoDB的空间使用情况分析并不简单,本文将由浅入深帮您查看,分析和优化云数据库MongoDB的空间使用。

查看空间使用

副本集模式

部署架构为副本集模式下,提供有多种查看空间使用的方法,您可以根据自身需求,由浅入深了解MongoDB的空间使用情况。

总体概览

在MongoDB控制台的“基本信息”页中会显示实例的总存储空间使用大小,但这里只有当前的空间的总使用率,没有具体的各类数据分别占用空间大小的信息,也没有空间使用的历史信息,如下图:

1.png

监控图分析

MongoDB副本集由多种角色组成,一个角色可能对应一个或多个物理节点。阿里云MongoDB对用户暴露Primary和Secondary节点,另外还提供有只读实例的角色。可以通过点击"监控信息",选择对应的角色查看MongoDB空间相关的监控情况,如下图:

2.png

其中一个MongoDB物理节点的空间使用由两大块组成,分别为data_size和log_size,其中这里的data_size是数据磁盘使用空间(不包括local库),主要包括collection打头的数据物理文件,index打头的索引物理文件,以及少部分元数据物理文件,比如WiredTiger.wt。

log_size包括local库的物理大小,mongodb运行日志大小,以及少部分的审计日志大小。

ins_size=data_size+log_size

3.png

详细分析

如果需要深入分析副本集中库或表的空间详细占用,除了MongoDB自带的db.stats(),db.$collection_name.stats()以外,我们推荐使用阿里云MongoDB控制台的提供的"CloudDBA-空间分析",通过"CloudDBA-空间分析",您可以实现以下目的

  • 查看库表空间概览,日均增长量,预测可用天数。
  • 查看异常库表空间使用。
  • 详细业务表的空间使用,包括索引和数据逻辑大小,压缩率分析,平均行长等更多内容。

更多的CloudDBA-空间分析内容参考:https://help.aliyun.com/document_detail/162422.html

更多mongodb官方提供的分析命令详解参考:

4.png

分片集群

在分片集群的部署模式下,由于一个集群下可能存在多个Shard,没有整体空间使用率的概念。所以控制台不再提供"基本信息"中的空间使用率。

监控图分析

阿里云MongoDB的监控信息中详细提供了集群组建mongos路由节点,config server配置节点以及shard节点的空间使用率。不过通常来说,mongos和config server节点不会成为空间瓶颈,建议选择忽略,直接查看各个shard中各个角色的空间使用情况,如下图:

5.png

详细分析

分片集群的空间使用的详细查看方法与副本集模式略有不同,需要逐个登录各个shard通过命令查看,在每个分片上的空间使用情况详情就与副本集情况完全一样。

另外一方面,分片集群中的空间问题除了空间使用率以外,还存在非常大量的"各shard空间使用不均匀"问题,后者非常难以分析,目前CloudDBA暂不支持。本文后续章节会重点带您了解和深入分析“不同分片下空间使用不均衡”,“同一副本集下各个角色空间使用不均衡”。

空间问题的疑难杂症分析和解决方法

空间问题上涨概要分析和一般解决思路

当收到磁盘空间报警后,一般的分析和解决思路如下:

  1. 确认当前的空间使用值,确认当前空间使用中各个库表的详细占用情况。
  2. 确认引起空间增长的主要源头,比如是日志类增长,还是具体的某个业务表写入暴涨。
  3. 确认当前的增长是否符合预期,针对不符合预期的大量写入场景做应用分析。
  4. 确认当前的数据是否存在大量碎片,能否通过回收碎片的方式回收空间。
  5. 确认是否需要做磁盘空间扩容,或者部署定时历史数据删除或TTL Index。
  6. 历史数据大量删除完成,通过compact或者重做副本集的方式回收碎片空间。

compact方法和compact期间对实例的影响

compact 一个集合,会加集合所在DB的互斥写锁,会导致该DB上所有的读写请求都阻塞,因为 compact 执行的时间可能很长,跟集合的数据量相关,所以强烈建议在业务低峰期执行,避免影响业务。

compact方法很简单,建议优先在备库上执行,并通过主备切换的方式来减少compact期间对业务的影响,指令为db.runCommand({compact: "collectionName"})。

另外,MongoDB4.4以后的官方版本,Compact命令将不再阻塞业务读写,更多compact的命令的使用方法和限制参考:

compact无效

如前文所述,在大量remove的场景下我们会需要使用compact来回收碎片空间。然而在极端场景下,compact操作虽然提示成功了,但实际上磁盘空间并没有回收,这应该算是一个BUG或者是MongoDB在compact设计上的缺陷,并不是只要存在碎片就一定能回收成功。compact的基本原理并不是立马开辟新的空间存放数据来替换原来的文件,而是将数据不断地往前面的空间空洞挪动,所以在某些场景下虽然存在空间空洞,但内部的compact算法并不能保证肯定可以复用这些空洞。针对这种compact失效的场景,如果纠结于空间使用,可以通过重建副本的方式解决。

还有一种场景,在MongoDB3.4以前的版本,compact或许还存在一个BUG:在大量删除数据后,compact无法回收索引文件,只对数据文件生效。这个可以通过使用命令db.$table_name.stats().indexSizes或者直接查看索引物理文件大小确认。针对这种情况,建议将内核版本升级至3.4以上。

journal log过大导致主备空间差距巨大

在极端情况下,journal log可能触发bug导致空间无限上涨,可以通过MongoDB运行日志查看类似以下内容:

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.

该bug的触发条件为宿主机的open files达到设置上限,导致MongoDB内部的log server清理线程中断,4.0以前的官方版本均有该问题,如果有遇到您可以将内核版本升级到4.0以上,或者可以通过重启mongod进程临时解决,具体的bug链接参考:https://jira.mongodb.org/browse/WT-4083

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

默认的官方MongoDB,oplog是一个固定集合,大小基本是固定的,主备之间的物理文件大小不会有太大差异。阿里云MongoDB出于oplog经常过期导致的节点recovering状态,开发了oplog自适应特性。也就是说,在极端场景出现主备延迟的情况下,实际oplog可以使用的大小不再受限于配置文件定义的固定集合大小,理论上可以达到用户申请磁盘容量的20%。这就造成了一个问题,当备库延迟恢复后,oplog之前占用的物理空间并不会回缩。

另外,处于备份和恢复效率的考虑,阿里云MongoDB使用物理备份的方式在Hidden备份mongodb实例,期间会涉及到大量的chepoint导致占用了更多的数据和日志空间。

针对以上场景,当空间占用量不是特别大的话通常建议直接忽略即可。也可以根据需要对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通过内部的哈希函数可以使得数据均匀地分布在不同地分片上,如下图所示:
6.png

而range分片一般是根据key的大小范围进行数据分布,所以往往会造成这样的一个现象:新插入的数据在一个热点的chunk上,不但会引起该chunk所在的shard磁盘IO过高,也会带来短期数据不均匀的场景。如下图所示,所有的数据写入chunk C所在分片,当chunk C写满以后会在本分片中split出新的chunk,后续通过集群负载均衡器Balancer迁移chunk,但这个迁移需要耗费大量的时间和IO,在一个高并发写入的场景下,数据的负载均衡速度可能跟不上数据写入速度,从而造成分片之间数据容量不均的问题。在这种使用场景下,不建议使用range分片策略。
7.png

更多的Sharding Key类型介绍参考:

sharding key字段选择不合理

通过sh.status()可以看到各个分片上的chunk数量基本一致,但实际上绝大部分数据都只存在部分chunk上,导致这些热点chunk所在的分片数据量远大于其他分片,通过查看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负载均衡主要考虑的是各个shard的chunk数量保持相当,就认为数据是均衡的,所以就会出现以上的极端场景:虽然各个shard数量相当,但实际数据严重倾斜。因为一个chunk内shardKey几乎完全相同但又触发到64M的chunk分裂阈值,这时就会分裂出一个空的chunk。久而久之,虽然chunk的数量变多了并且完成了chunk的迁移,但实际上迁移走的chunk都是空的chunk,造成了chunk数量均衡但实际数据不均衡的情况。(这应该是Balancer在迁移chunk时基于代价的考虑,认为空chunk迁移代价更低,所以优先选了空的chunk迁移)

    更多split的介绍参考:

针对这种情况,只能在架构上重新设计,选择合适的区分度较高的列作为sharding key。

部分db未做sharding

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

除了上述情况,比较容易引起该问题的使用场景通常是因为从一个源端mongos集群导入到一个新的mongos集群,而逻辑导入过程中忽略了一步:实现在目标端mongos集群做好sharding设计,因为逻辑导入并不会自动做sharding设计,这一步需要事先做好。

针对这种问题,我们建议:

  • 如果是因为目标集群初始化导入,导入之前做好分片设计。
  • 如果不做sharding的库很多且数据量基本相当,Mongos提供有movePriamy命令将指定db迁移到指定分片。
  • 如果存在某个db的数据量极大且未做sharding,建议对其做sharding设计或者将其拆分出来当作单一的副本集对待。
  • 即使出现这种情况,如果磁盘总量足够充裕,建议忽略。

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

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

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

更多movechunk的介绍参考:

阿里云MongoDB产品在空间使用优化上的规划

计算存储分离

当前的阿里云MongoDB单个物理节点最大支持的存储空间是3T,如果单实例或副本集模式下的节点数据量超过3T就必须业务拆分或者升级至分片集群,而且规格扩容涉及到数据迁移会导致耗时较长。

阿里云MongoDB在副本集部署模式下即将支持云盘以实现计算存储分离。在云盘存储下,单个节点的数据存储上限将达到数十T,以及云原生架构带来的分钟级扩容能力。

ECS快照备份

在高版本的阿里云MongoDB实例中,由于oplog多线程回放技术的越发成熟,基本上不会再有备库延迟问题,所以阿里云MongoDB内核层面不再对oplog做定制化改造,与官方的"固定集合"形态保持一致,备库延迟引起的oplog放大问题通过升级至最新版内核即可得到解决。

另外,当前阿里云MongoDB正在研发采用ECS快照技术备份MongoDB实例,当故障发生时可绕过耗时的OSS物理备份下载,达到分钟级的恢复能力。并且使用ECS快照备份后,传统物理备份方式可能导致Hidden节点空间上涨的问题也会得到解决。

Compact指令的内核改造优化

MongoDB4.4的Compact指令并不会阻塞读写,阿里云MongoDB在内核层面将该patch移植至云数据库    MongoDB 3.4及以上版本,通过DAS控制台点击的方式实现空间碎片整理的产品化。





相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
NoSQL Oracle MongoDB
【最佳实践】MongoDB导出导入数据
【最佳实践】MongoDB导出导入数据
506 2
|
运维 NoSQL 安全
【最佳实践】高可用mongodb集群(1分片+3副本):规划及部署
结合我们的生产需求,本次详细整理了最新版本 MonogoDB 7.0 集群的规划及部署过程,具有较大的参考价值,基本可照搬使用。 适应数据规模为T级的场景,由于设计了分片支撑,后续如有大数据量需求,可分片横向扩展。
1160 1
|
NoSQL MongoDB 索引
【最佳实践】MongoDB导入数据时重建索引
【最佳实践】MongoDB导入数据时重建索引
277 0
|
4月前
|
存储 NoSQL JavaScript
MongoDB存储过程实战:聚合框架、脚本、最佳实践,一文全掌握!
【8月更文挑战第24天】MongoDB是一款备受欢迎的文档型NoSQL数据库,以灵活的数据模型和强大功能著称。尽管其存储过程支持不如传统关系型数据库,本文深入探讨了MongoDB在此方面的最佳实践。包括利用聚合框架处理复杂业务逻辑、封装业务逻辑提高复用性、运用JavaScript脚本实现类似存储过程的功能以及考虑集成其他工具提升数据处理能力。通过示例代码展示如何创建订单处理集合并定义验证规则,虽未直接实现存储过程,但有效地演示了如何借助JavaScript脚本处理业务逻辑,为开发者提供更多实用指导。
77 2
|
7月前
|
存储 监控 NoSQL
【MongoDB 专栏】MongoDB 分片策略与最佳实践
【5月更文挑战第10天】MongoDB 分片是应对大数据量的扩展策略,涉及哈希和范围分片两种策略。分片架构包含分片服务器、配置服务器和路由服务器。最佳实践包括选择合适分片键、监控调整、避免热点数据等。注意数据分布不均和跨分片查询的挑战。通过实例展示了如何在电商场景中应用分片。文章旨在帮助理解并优化 MongoDB 分片使用。
270 3
【MongoDB 专栏】MongoDB 分片策略与最佳实践
|
7月前
|
NoSQL 测试技术 定位技术
【MongoDB 专栏】MongoDB 的地理空间索引与位置查询
【5月更文挑战第10天】MongoDB 支持地理空间数据处理,提供2dsphere(球面)和2d(平面)索引,适用于地图导航、物流、社交网络等领域。通过创建索引,可加速位置查询,如查询范围、最近邻及地理空间聚合。案例包括地图应用、物流追踪和社交网络。注意数据准确性、索引优化和性能测试,以发挥其在地理空间处理中的潜力。学习此功能,为应用开发解锁更多可能性!
269 2
【MongoDB 专栏】MongoDB 的地理空间索引与位置查询
|
5月前
|
存储 NoSQL Java
使用MongoDB实现NoSQL数据库的最佳实践
使用MongoDB实现NoSQL数据库的最佳实践
|
6月前
|
NoSQL 安全 MongoDB
精准数据清理:掌握 MongoDB 删除集合的方法与最佳实践
精准数据清理:掌握 MongoDB 删除集合的方法与最佳实践
213 0
|
6月前
|
存储 NoSQL 数据管理
MongoDB关系处理:优化数据管理、提升性能的最佳实践
MongoDB关系处理:优化数据管理、提升性能的最佳实践
|
6月前
|
存储 NoSQL MongoDB
深入解析 MongoDB 与 Python:基本语法、实用示例与最佳实践
深入解析 MongoDB 与 Python:基本语法、实用示例与最佳实践
100 0

相关产品

  • 云数据库 MongoDB 版