开发者社区> 张友东(林青)> 正文

MongoDB CPU 利用率高,怎么破?

简介: 经常有用户咨询「MongoDB CPU 利用率很高,都快跑满了」,应该怎么办? 遇到这个问题,99.9999% 的可能性是「用户使用上不合理导致」,本文主要介绍从应用的角度如何排查 MongoDB CPU 利用率高的问题 Step1: 分析数据库正在执行的请求 用户可以通过 Mongo Shell 连接,并执行 db.currentOp() 命令,能看到数据库当前正在执行的操作,如下是该命令的一个输出示例,标识一个正在执行的操作。
+关注继续查看

经常有用户咨询「MongoDB CPU 利用率很高,都快跑满了」,应该怎么办?

遇到这个问题,99.9999% 的可能性是「用户使用上不合理导致」,本文主要介绍从应用的角度如何排查 MongoDB CPU 利用率高的问题

Step1: 分析数据库正在执行的请求

用户可以通过 Mongo Shell 连接,并执行 db.currentOp() 命令,能看到数据库当前正在执行的操作,如下是该命令的一个输出示例,标识一个正在执行的操作。重点关注几个字段

  • client:请求是由哪个客户端发起的?
  • opid:操作的opid,有需要的话,可以通过 db.killOp(opid) 直接干掉的操作
  • secs_running/microsecs_running: 这个值重点关注,代表请求运行的时间,如果这个值特别大,就得注意了,看看请求是否合理
  • query/ns: 这个能看出是对哪个集合正在执行什么操作
  • lock*:还有一些跟锁相关的参数,需要了解可以看官网文档,本文不做详细介绍

    db.currentOp 文档在这里,多看官网文档

    
        {
            "desc" : "conn632530",
            "threadId" : "140298196924160",
            "connectionId" : 632530,
            "client" : "11.192.159.236:57052",
            "active" : true,
            "opid" : 1008837885,
            "secs_running" : 0,
            "microsecs_running" : NumberLong(70),
            "op" : "update",
            "ns" : "mygame.players",
            "query" : {
                "uid" : NumberLong(31577677)
            },
            "numYields" : 0,
            "locks" : {
                "Global" : "w",
                "Database" : "w",
                "Collection" : "w"
            },
            ....
        },
    

这里先要明确一下,通过 db.currentOp() 查看正在执行的操作,目的到底是什么?

并不是说我们要将正在执行的操作都列出来,然后通过 killOp 逐个干掉;这一步的目的是要看一下,是否有「意料之外」的耗时请求正在执行。

比如你的业务平时 CPU 利用率不高,运维管理人员连到数据库执行了一些需要全表扫描的操作,然后突然 CPU 利用率飙高,导致你的业务响应很慢,那么就要重点关注下那些执行时间很长的操作。

一旦找到罪魁祸首,拿到对应请求的 opid,执行 db.killOp(opid) 将对应的请求干掉。

如果你的应用一上线,cpu利用率就很高,而且一直持续,通过 db.currentOp 的结果也没发现什么异常请求,可以进入到 Step2 进行更深入的分析。

Step2:分析数据库慢请求

MongoDB 支持 profiling 功能,将请求的执行情况记录到同DB下的 system.profile 集合里,profiling 有3种模式

profiling 设置文档在这里,多看官网文档

  • 关闭 profiling
  • 针对所有请求开启 profiling,将所有请求的执行都记录到 system.profile 集合
  • 针对慢请求 profiling,将超过一定阈值的请求,记录到system.profile 集合

默认请求下,MongoDB 的 profiling 功能是关闭,生产环境建议开启,慢请求阈值可根据需要定制,如不确定,直接使用默认值100ms。

operationProfiling:
  mode: slowOp
  slowOpThresholdMs: 100

基于上述配置,MongoDB 会将超过 100ms 的请求记录到对应DB 的 system.profile 集合里,system.profile 默认是一个最多占用 1MB 空间的 capped collection。

查看最近3条 慢请求,{$natrual: -1} 代表按插入数序逆序
db.system.profile.find().sort({$natrual: -1}).limit(3)

在开启了慢请求 profiling 的情况下(MongoDB 云数据库是默认开启慢请求 profiling的),我们对慢请求的内容进行分析,来找出可优化的点,常见的包括。

profiling的结果输出含义在这里,多看官网文档

CPU杀手1:全表扫描

全集合(表)扫描 COLLSCAN,当一个查询(或更新、删除)请求需要全表扫描时,是非常耗CPU资源的,所以当你在 system.profile 集合 或者 日志文件发现 COLLSCAN 关键字时,就得注意了,很可能就是这些查询吃掉了你的 CPU 资源;确认一下,如果这种请求比较频繁,最好是针对查询的字段建立索引来优化。

一个查询扫描了多少文档,可查看 system.profile 里的 docsExamined 的值,该值越大,请求CPU开销越大。

关键字:COLLSCAN、 docsExamined

CPU杀手2:不合理的索引

有的时候,请求即使查询走了索引,执行也很慢,通常是因为索引建立不太合理(或者是匹配的结果本身就很多,这样即使走索引,请求开销也不会优化很多)。

如下所示,假设某个集合的数据,x字段的取值很少(假设只有1、2),而y字段的取值很丰富。

{ x: 1, y: 1 }
{ x: 1, y: 2 }
{ x: 1, y: 3 }
......
{ x: 1, y: 100000} 
{ x: 2, y: 1 }
{ x: 2, y: 2 }
{ x: 2, y: 3 }
......
{ x: 1, y: 100000} 

要服务 {x: 1: y: 2} 这样的查询

db.createIndex( {x: 1} )         效果不好,因为x相同取值太多
db.createIndex( {x: 1, y: 1} )   效果不好,因为x相同取值太多
db.createIndex( {y: 1 } )        效果好,因为y相同取值很少
db.createIndex( {y: 1, x: 1 } )  效果好,因为y相同取值少

至于{y: 1} 与 {y: 1, x: 1} 的区别,可参考MongoDB索引原理复合索引官方文档 自行理解。

一个走索引的查询,扫描了多少条索引,可查看 system.profile 里的 keysExamined 字段,该值越大,CPU 开销越大。

关键字:IXSCAN、keysExamined

CPU杀手3:大量数据排序

当查询请求里包含排序的时候,如果排序无法通过索引满足,MongoDB 会在内存李结果进行排序,而排序这个动作本身是非常耗 CPU 资源的,优化的方法仍然是建立索引,对经常需要排序的字段,建立索引。

当你在 system.profile 集合 或者 日志文件发现 SORT 关键字时,就可以考虑通过索引来优化排序。当请求包含排序阶段时, system.profile 里的 hasSortStage 字段会为 true。

关键字:SORT、hasSortStage

其他还有诸如建索引,aggregationv等操作也可能非常耗 CPU 资源,但本质上也是上述几种场景;建索引需要全表扫描,而vaggeregation 也是遍历、查询、更新、排序等动作的组合。

Step3: 服务能力评估

经过上述2步,你发现整个数据库的查询非常合理,所有的请求都是高效的走了索引,基本没有优化的空间了,那么很可能是你机器的服务能力已经达到上限了,应该升级配置了(或者通过 sharding 扩展)。

当然最好的情况时,提前对 MongoDB 进行测试,了解在你的场景下,对应的服务能力上限,以便及时扩容、升级,而不是到 CPU 资源用满,业务已经完全撑不住的时候才去做评估。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
9730 0
使用SSH远程登录阿里云ECS服务器
远程连接服务器以及配置环境
13541 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
20434 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
18709 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
25094 0
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
17140 0
windows server 2008阿里云ECS服务器安全设置
最近我们Sinesafe安全公司在为客户使用阿里云ecs服务器做安全的过程中,发现服务器基础安全性都没有做。为了为站长们提供更加有效的安全基础解决方案,我们Sinesafe将对阿里云服务器win2008 系统进行基础安全部署实战过程! 比较重要的几部分 1.
11839 0
+关注
张友东(林青)
阿里云高级技术专家
105
文章
18
问答
来源圈子
更多
阿里云数据库:帮用户承担一切数据库风险,给您何止是安心!支持关系型数据库:MySQL、SQL Server、PostgreSQL、PPAS(完美兼容Oracle)、自研PB级数据存储的分布式数据库Petadata、自研金融级云数据库OceanBase支持NoSQL数据库:MongoDB、Redis、Memcache更有褚霸、丁奇、德哥、彭立勋、玄惭、叶翔等顶尖数据库专家服务。
+ 订阅
相关文档: 云数据库 OceanBase 版 可信账本数据库 云原生关系型数据库 PolarDB PostgreSQL引擎
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载