You need to enable JavaScript to run this app.
导航
如何解决 CPU 使用率过高的问题
最近更新时间:2024.09.23 11:36:13首次发布时间:2022.01.14 18:24:47

使用云数据库 MySQL 版时,如果实例的 CPU 使用率过高或接近 100%,可能会导致数据读写处理缓慢、连接延迟加剧,甚至在删除操作时出现错误,从而严重影响业务的正常运行。本文中提供了几种常见原因的定位以及解决方法。

问题确认

查看 CPU 使用率的监控项,确认实例当前的 CPU 使用率。

  1. 实例列表页面,单击目标实例的实例名称,进入实例信息页。

  2. 在页面上方,单击监控告警页签。

  3. 资源监控分类下,查看 CPU使用率

    说明

    可按照节点维度查看实例各节点的 CPU 使用率

快速止损

如果 CPU 使用率已经非常接近 100%,可以通过以下两种手段快速恢复实例性能。

  • 重启实例
  • 切换实例主节点

重启实例

注意

重启实例的耗时取决于实例的负载状态,会导致业务有 1~2 次闪断,请谨慎操作。建议您增加应用的重连机制,可以大幅降低数据库连接闪断对业务的影响。

  1. 实例列表页面,单击目标实例操作列的 > 重启实例

  2. 在弹出的对话框中,分别选择重启范围所有节点重启时间立即重启后,单击确定。

    说明

    可按照节点维度查看实例各节点的 CPU 使用率。如果 CPU 使用率过高的节点为主节点,重启范围应为所有节点;如果 CPU 使用率过高的节点为某个只读节点,重启范围应为指定只读节点,并在只读节点下拉列表中选择相应只读节点。

    说明

    更多详细信息,请参见重启实例

切换实例主节点

说明

切换主节点期间数据库将有 1~2 次闪断,请谨慎操作,同时建议您增加应用程序的重连机制。

  1. 实例列表页面,单击目标实例名称,进入实例信息页签。

  2. 单击连接管理页签,在实例拓扑区域,将鼠标指针指向备节点,在弹出的窗口中单击切换主节点,在弹出的对话框中单击确定,即可完成主备节点的切换。

说明

更多详细信息,请参见切换主节点

原因定位及解决

异常 SQL 负载

QPS 原因

  • 原因分析

    TP 系统 SQL 执行一般比较快,MySQL 实例的 CPU 不会在没有负载的情况下无故升高,大多数 CPU 使用率升高是由于异常的 SQL 负载导致资源被过度消耗。因此要首先确认是否流量发生了变化、是否上线了新的 SQL。具体方式是在数据库工作台查看实例的总查询数监控项。
      操作路径:登录 数据库工作台 > 观测诊断 > 性能监控 > 总查询数。更详细信息,请参见查看性能监控指标

  • 解决办法

    通过数据库工作台的慢日志分析和全量 SQL 洞察功能确定是哪些 SQL 引起的 CPU 负载升高,并通过 SQL 限流来限制 SQL 的执行频率,防止异常负载打满 CPU。

    说明

    全量 SQL 洞察和 SQL 限流当前为数据库工作台的邀测功能,如需使用请提交工单申请。

    1. 定位 SQL

      • 慢日志分析
        进行慢日志分析的操作路径:登录 数据库工作台 > 观测诊断 > 慢日志分析。更详细信息,请参见慢日志分析


        进行慢日志分析时,可以重点关注以下信息:

        • 平均锁等待时间 判断慢 SQL 是 off-CPU 多还是 on-CPU 多。等待时间长说明 SQL 长时间不占用 CPU,反之则证明 on-CPU 时间多。

        • 平均扫描行数 一般与跟 CPU 使用率正相关。

        • 重点关注Rows_examined字段,如果很高说明需要消耗更多资源扫描行数会占用更多 CPU 资源。

          # Time: 2022-12-14T15:01:34.892085Z
          # User@Host: root[root] @ localhost []  Id:     8
          # Query_time: 3.985637  Lock_time: 0.000138 Rows_sent: 165346 Rows_examined: 9900000 Thread_id: 8 Errno: 0 Killed: 0 Bytes_received: 0 Bytes_sent: 4848540 Read_first: 0 Read_last: 0 Read_key: 1 Read_next: 9900000 Read_prev: 0 Read_rnd: 0 Read_rnd_next: 0 Sort_merge_passes: 0 Sort_range_count: 0 Sort_rows: 0 Sort_scan_count: 0 Created_tmp_disk_tables: 0 Created_tmp_tables: 0 Start: 2022-12-14T15:01:30.906448Z End: 2022-12-14T15:01:34.892085Z Schema: slow Rows_affected: 0
          SET timestamp=1671030090;SELECT * FROM `student` WHERE id>100000 AND `name`='Yunxi';
          
      • SQL 洞察
        进行 SQL 洞察的操作路径:登录数据库工作台 > 观测诊断 > 全量 SQL 洞察。更详细信息,请参见全量 SQL 洞察


              进行 SQL 洞察时,可关注 TotalExecTime,其表示一段时间内执行 SQL 的耗时,可对其进行降序排序,定位到耗时最多的 SQL。

    2. 处理 SQL
      定位到 SQL 后,可通过 SQL 限流或 KILL 会话的方式进行处理。

      • SQL 限流
        定位到问题 SQL 后,可以通过 SQL 限流限制 SQL 的执行频率。
        操作路径:

        1. 登录 数据库工作台 > 观测诊断 > 会话管理 > SQL 限流 > 打开SQL限流功能 > 创建任务

        2. 在创建 SQL 限流任务窗口中,输入问题 SQL,调整最大并发数(最大并发数为 0 时会完全屏蔽该 SQL),单击关键字生成和校验拆分关键词,关键词会用波浪线(~)分隔。

        3. 单击确定提交任务。

          说明

          更多详细信息,请参见SQL 限流管理

      • KILL 会话

        1. 登录 数据库工作台 > 观测诊断 > 会话管理
        2. 实时会话区域,关注会话的 TimeState。如果某会话的 State 为 updating,但 Time 的数值已很大,则需要关注处理。

扫描行数多

  • 原因分析

    逻辑读数量与 CPU 消耗一般正相关,如果逻辑读数量增加,基本可以确认 CPU 使用率升高与 SQL 有关,而不是数据库的环境发生了变化,可以通过查看以下监控项确认读取行数和 CPU 使用率的相关性。

    • InnoDB 读取量

    • InnoDB 平均每秒从 BufferPool 读取页的次数(逻辑读)

    操作路径:登录 数据库工作台 > 观测诊断 > 性能监控。更详细信息,请参见查看性能监控指标

  • 解决办法

    • 执行 show processlist 命令,或通过数据库工作台的慢日志分析全量 SQL 洞察确定是哪些 SQL 引起的 CPU 负载升高,并通过 KILL SQL 或 SQL 限流的方式来解决。KILL SQL 的方式如下:

      1. 查看正在运行的事务,看是否有长时间运行的 SQL。

        mysql> select * from information_schema.innodb_trx \G;
        *************************** 1. row ***************************
                            trx_id: 1335
                         trx_state: LOCK WAIT
                       trx_started: 2023-12-28 17:36:35
             trx_requested_lock_id: 1335:25:3:2
                  trx_wait_started: 2023-12-28 17:45:31
                        trx_weight: 2
               trx_mysql_thread_id: 7432 # 跟processlist的ID是同一个值
                         trx_query: update t1 set c2 = c2 + 200 where c1 = 1
               trx_operation_state: starting index read
                 trx_tables_in_use: 1
                 trx_tables_locked: 1
                  trx_lock_structs: 2
             trx_lock_memory_bytes: 1160
                   trx_rows_locked: 3
                 trx_rows_modified: 0
           trx_concurrency_tickets: 0
               trx_isolation_level: REPEATABLE READ
                 trx_unique_checks: 1
            trx_foreign_key_checks: 1
        trx_last_foreign_key_error: NULL
         trx_adaptive_hash_latched: 0
         trx_adaptive_hash_timeout: 0
                  trx_is_read_only: 0
        trx_autocommit_non_locking: 0
        
      2. 执行 KILL 命令,防止该 SQL 继续消耗 CPU。使用的 ID 是 processlist 中的 ID。

        mysql> KILL 7432  -- from processlist
        
    • 优化 SQL,减少逻辑读。对于扫描行数过多但是不好优化的 SQL,可以通过添加索引来提升过滤性。

执行计划错误

导致执行计划错误的原因有两种,一种是统计数据滞后,另一种是优化器问题。

  • 统计数据滞后

    • 原因分析

      MySQL 会自动更新表统计信息来帮助优化器选择适合的 access path,如果统计信息不准确,优化器的判断可能受到影响;如实际行数远大于统计信息的行数,优化器可能会认为全表扫描效率更高从而导致执行计划错误,扫描过多行导致 CPU 使用率升高。执行以下命令查看统计信息,可判断统计数据是否有滞后。

      select * from innodb_table_stats where database_name='' and table_name='';
      
    • 解决办法

      不要依赖 MySQL 定时更新统计信息的机制,对频繁修改的大表进行统计数据评估,查看mysql.innodb_table_statslast_update 字段即可。对于长期没有更改的统计数据进行重点关注,并在低峰期手动 analyze table 更新统计信息。

  • 优化器问题

    • 原因分析

      使用 order by limit 导致统优化器判断不准使用了全表扫描。

    • 解决办法

      • 查看优化器参数 select @@optimizer_switch\G ,尝试关闭问题优化器参数,如prefer_ordering_index

      • FORCE INDEX 指定索引。

连接线程池异常

  • 原因分析

    如果配置的并发数超过了当前配置的合理值,导致 MySQL 活跃线程数高,那么在并发上升时,MySQL 可能因为活跃线程数过多而发生「塞车」,导致 CPU 使用率增加。可以通过查看监控项运行线程数确认读取行数和 CPU 使用率的相关性。
      操作路径:登录 数据库工作台 > 观测诊断 > 性能监控 > 运行线程数。更详细信息,请参见查看性能监控指标

  • 解决办法

    • 控制 server 层并发,关注 thread_pool_size * thread_pool_oversubscribe 的值,这两个参数乘积为最多允许的活跃线程数,经验值为不要超过CPU核心数的2-3倍

    • 控制 innodb 层并发,配置 innodb_thread_concurrency

    • 及时升级内核版本。如有需要,请提交工单联系技术支持进行升级。

隔离级别

  • 原因分析

    云数据库 MySQL 版默认采用的是 Read-Committed(RC) 隔离级别,但允许用户设置为 Repeatable-Read(RR)级别。在 RR 级别下有可能会有 RC 隔离级别下没有的 CPU 使用率升高的问题。

  • 解决办法

    • 确认 RR 是否是为需要的隔离级别,如果不是可以调整为RC

    • 如果历史链表长造成扫描量上升可以配置 auto kill,kill 掉执行时间过长的 SQL。

提升实例规格

经过以上手段进行排查和解决后,如果 CPU 使用率仍持续升高,则可能是业务压力导致的正常情况,此时可考虑通过常规变配或临时升配提高实例规格,增加 CPU 核数可降低实例压力。
关于如何对实例进行常规变配或临时升配,请参见以下文档:

说明

临时升配当前为云数据库 MySQL 版的邀测功能,如需使用,请提交工单申请。