往期分享
RDS MySQL
RDS PostgreSQL
RDS SQL Server
Redis
MongoDB
概述
阿里云数据库MongoDB的IOPS使用率是一个非常重要的监控指标,IOPS使用率达到或接近100%后容易引起业务响应缓慢,甚至导致业务不可用的情形。一般云数据库厂商为了避免宿主机出现IO争抢,会使用Cgroup等技术进行实例间的IO隔离和IOPS限制,即不同规格的实例配置对应不同的IOPS使用上限。
本文将由浅入深帮您查看、分析和优化云数据库MongoDB的IOPS使用率。
查看IOPS使用
监控图查看
首先需要确认该实例的最大IOPS上限,通过点击"基本信息"可以查看,如下图:
不同实例规格对应的IOPS使用上限参考:
https://help.aliyun.com/document_detail/57141.html
通过点击"监控信息"可以查看到当前的IOPS使用量,因为绝大部分情况下阿里云数据库MongoDB的data目录和log目录使用同一块盘,所以IOPS使用量=data_iops=log_iops。
命令行查看
在监控图展示上,目前阿里云MongoDB仅限制IOPS,也仅展示IOPS的相关信息。在实际的IO问题中,我们同样可能需要关注IO吞吐量,IO延迟情况,通过db.serverStatus().systemInfo命令可以查看IO相关的其他指标监控,不过所有监控项都是自MongoDB启动以来的累加值,并不建议直接查看。
如果用户有自行开发更为详细的MongoDB性能指标,可以基于上述命令的累加数值获取更多的MongoDB IO指标。
MongoDB 磁盘IO问题常见原因和优化策略
对于云数据库MongoDB来说,底层的磁盘硬件性能对用户透明,完全交由云厂商负责,用户只需要核心关注业务的正确使用MongoDB,以及配置合适的内存和IOPS上限。
通常来说,MongoDB的IO问题与内存的CacheSize大小息息相关。CacheSize越大,表示能够缓存的热数据越大,那么系统需要的磁盘IO量也就越低,出现IO瓶颈的概率越低;反之,CacheSize越小,表示能否缓存的热数据越少,系统刷脏也更频繁,实例出现IO压力的概率也就越大。
您可以通过mongostat或者阿里云数据库自治服务DAS实时查看当前的cache dirty,目前阿里云数据库MongoDB暂不支持cache dirty历史情况查看。如果出现 dirty>20%,并一直持续,说明内存淘汰压力很大,用户的请求线程会阻塞参与page淘汰,请求延时就会增加,这时可以考虑"扩大内存"或者"扩大IOPS"。
更多mongostat的使用方式可以参考:https://docs.mongodb.com/v4.2/reference/program/mongostat/
还有一些与磁盘IO相关的参数和配置,比如MongoDB Journal和运行日志刷盘,WriteConcern设置,分片集群的MoveChunk等,这些因素我们建议用户根据实际业务需求情况设置即可,一般来说,不必为了尽可能地提高IO能力刻意修改。
关于更多Journal内容可参考:https://docs.mongodb.com/manual/core/journaling/
关于更多WriteConcern内容可参考:https://docs.mongodb.com/manual/reference/write-concern/
对于阿里云MongoDB来说,我们更推荐配置好合适的实例规格的同时,重点关注Index的优化和部分应用系统的写入优化。
如何配置合适的实例规格
一般很难事先预估热数据与CacheSize的比例设置为多少最合适,这是性能与实例费用的一个折衷。通用经验下,我们建议在MongoDB实例在日常态运行过程中满足业务RT要求的情况下,保证每日的峰值CPU使用率和IOPS使用率控制在50%以内。
Index优化
SQL全表扫描或者使用了不恰当的Index,比如导出全表数据期间,消耗的IO必然很大。另一方面,过多累赘的Index创建也会产生更多的数据规模,导致WiredTiger Cache只能缓存更小的热数据,业务数据写操作过程中也同样多一次IO操作去更新Index,从而影响IO性能。
所以在避免滥用Index的情况下,需要为每个Query创建最合适的Index,关于这部分内容,可以参考:https://docs.mongodb.com/manual/indexes/
业务架构和运维优化
在业务架构层面,要避免磁盘IO成为瓶颈,主要从以下几个方面入手:
控制并发写入/读取线程数
MongoDB是多线程应用,但是我们并不推荐"极致压榨"MongoDB实例本身的性能,过高的并发写入速度和复杂查询并发数,容易引起IOPS瓶颈,甚至导致Secondary节点持续延迟。具体的MongoDB IO压力可以参考上文提到的mongostat中的dirty数值。
如果业务写入量就是大到超出单机瓶颈,建议升级至MongoDB分片集群模式,通过数据的水平拆分来线性扩容MongoDB的写入性能。
尽可能避免峰值写入
部分业务,比如日志系统的定期写入或者游戏系统中用户信息的批量持久化,容易造成一个一个IOPS峰值。针对这种情况,在当前的实例配置不足以支撑如此峰值写入的情况下,我们建议业务侧改造为平滑写入,比如给每一个批量写入操作添加一个随机时间片。
避免业务高峰期间做运维操作
一些对性能影响较大的运维操作本质上也是认为造成了IOPS峰值,在无法避免的情况下,应该尽可能避免在业务高峰期执行。常见的容易引起IO高峰的运维操作有批量写入/更新/删除数据,添加Index,对集合执行Compact操作,批量导出数据等。