You need to enable JavaScript to run this app.
导航

MongoDB CPU 使用率高排查手册

最近更新时间2023.11.07 10:27:40

首次发布时间2023.02.02 11:01:29

在使用文档数据库 MongoDB 版的过程中,若存在查询语句不够优化(如未设置合理索引)、请求并发量大、计算任务过重等情况时,可能会使数实例 CPU 使用率变高,从而导致数据读写变慢、超时增加等问题,甚至严重影响业务的正常运行。本文从查询语句、慢日志、执行计划等方面,介绍如何排查并定位 MongoDB 实例 CPU 使用率高的问题。

查看正在运行的语句

您可以参考如下步骤查看数据库中正在运行的语句:

  1. 通过 Mongo Shell 工具连接实例。具体操作步骤,请参见通过 Mongo Shell 工具连接实例

  2. 在目标实例中执行 db.currentOp(),查看数据库中正在运行的语句。

    说明

    关于 db.currentOp() 命令的更多用法,请参见 db.currentOp()

    部分返回结果示例如下。

    {
                            ...
                            "client" : "192.168.***.***:****",
                            "appName" : "MongoDB Shell",
                            "active" : true,
                            "currentOpTime" : "2023-01-28T16:45:51.243+0800",
                            "opid" : 7339****,
                            ...
                            "secs_running" : NumberLong(0),
                            "microsecs_running" : NumberLong(137),
                            "op" : "command",
                            "ns" : "admin.$cmd.aggregate",
                            "command" : {
                                    "currentOp" : 1,
                                    ...
                                    "$db" : "admin"
                            },
                            "numYields" : 0,
                            "locks" : {
                            },
                            "waitingForLock" : false,
                            "lockStats" : {
                            },
                            ...
                            
    }
    

    在返回结果中,您需要重点关注如下字段。

    说明

    您可以查看并分析返回结果中是否存在耗时很长的请求。例如,您平时业务的 CPU 使用率正常,但执行了一些需要全表扫描的操作后导致 CPU 使用率升高,业务响应缓慢,此时就需要重点关注执行耗时非常长的请求。关于返回结果中各字段的更多信息,请参见 currentOp

    字段说明
    client发起请求的客户端信息(包括 IP 地址和端口号)。
    opid当前操作的标识符。您可以通过 db.killOp(opid) 命令来终止当前操作。关于 db.killOp() 命令的更多详情,请参见 db.killOp()
    secs_running当前操作的持续时间(即操作开始时间与当前时间的差值),单位:秒。如果操作持续时间较长,建议您查看请求是否合理。
    microsecs_running当前操作持续的时间(即操作开始时间与当前时间的差值),单位:微秒。如果操作持续较长,建议您查看请求是否合理。
    ns当前操作的目标集合。
    op当前操作的类型,例如 query(读取)、update(更新)、insert(插入)、command(命令)等操作类型。
    locks与锁相关的信息,详情请参见并发(Concurrency)说明

查询慢日志

如果您的实例 CPU 使用率异常升高,但执行了 db.currentOp() 命令后,并没有在输出结果中发现耗时异常的请求,那么您可以通过分析慢请求来帮助进一步排查和定位问题。
默认情况下,文档数据库 MongoDB 版会将执行时长超过 100 毫秒的请求记录到慢日志中。您可以参考如下操作步骤来分析慢日志,帮助找到 CPU 使用率异常升高的原因。

  1. 通过 MongoDB 控制台查询慢日志。具体操作步骤,请参见查询慢日志

  2. 分析慢日志,查找引起 MongoDB 实例的 CPU 使用率异常升高的原因。
    下表列举了慢日志中的部分关键字以及导致慢日志的原因,并提供了一些处理建议供您参考。

    导致慢日志出现的原因关键字处理建议

    执行了全表扫描

    • COLLSCAN
    • docsExamined
    • 如果慢日志中的请求出现了 COLLSCAN 关键字,表示这些请求执行了全表扫描,全表扫描会非常占用大量 CPU 资源。如果这些请求比较频繁,您可以对查询的字段建立索引来优化。
    • 您可以通过 docsExamined 字段值,帮助确认当前查询请求扫描了多少文档,该值越大,表示当前请求所占用的 CPU 越多。

    索引使用不合理

    • IXSCAN
    • keysExamined
    • 如果慢日志中出现了 IXSCAN 关键字,表示该请求使用了索引。
    • 您可以进一步查看 keysExamined 字段值,帮助确认当前请求扫描了多少条索引。该值越大,表示 CPU 占用越多。
      索引建立的是否合理,对查询的请求开销和执行速度影响很大。索引不是越多越好,索引过多会影响写入、更新的性能。如果您的应用偏向于写操作,索引可能会影响性能。建议您根据业务特点建立合理的索引。

      说明

      若您已建立了合理的索引,但执行查询计划时发现并没有使用最优索引。此时,您可以通过 PlanCache.clear() 命令清除实例的查询缓存,让实例从 PlanCache 中重新选择索引。更多详情,请参见为什么有时实例并没有选择最优索引?

    存在大量数据排序

    • SORT
    • hasSortStage
    • 如果在慢日志中出现了SORT关键字,您可以考虑通过索引来优化排序。
    • 当查询请求中的 hasSortStage 字段为 true 时,表示当前请求中存在排序。
      如果排序无法通过索引满足,MongoDB 会在查询结果中进行排序,而排序操作会消耗大量 CPU 资源,这种情况下,您可以对需要经常排序的字段建立索引,来优化查询,减少 CPU 资源的占用。

分析执行计划

MongoDB 提供了 explain() 命令来查看指定查询的查询计划统计信息,例如所用的索引、查询语句能否被索引覆盖、所扫描的索引项数量、所读取的文档数量、所返回的文档数量、执行查询所需的时间等信息。
您可以通过查询计划中的上述信息帮助建立合适的索引,来优化查询从而减少 CPU 资源消耗。关于 explain() 返回结果的更多信息,请参见 Explain Results

使用与业务负载相匹配的实例

根据数据库正在运行的语句、慢请求以及执行计划的分析结果,对数据库请求使用了合理索引后, 如果 CPU 使用率高的问题仍然存在,那么您还需要评估 MongoDB 实例的当前配置是否能够满足业务需求。
您可以通过查看监控数据分析实例资源的使用状态,并对 MongoDB 数据库进行性能测试,帮助了解当前实例配置是否满足您的业务所需要的设备性能和服务能力。如果需要升级 MongoDB 实例的配置,具体操作步骤请参见变更实例配置