更新时间:2024-09-05 GMT+08:00

CPU使用率高问题定位及处理方法

指标异常说明(影响)

系统CPU使用率:指的是整个系统CPU运行时间占总CPU时间的百分比。

CPU使用率分别有用户态CPU时间占比和内核态CPU时间占比:

  • 用户态:是用户程序运行时的状态。
  • 内核态:是操作系统的管理程序运行时的状态,包含系统调用,内核线程和中断。

当CPU打满的时候,会使业务变慢。

问题排查思路

引起CPU爆满的原因一般分为三种:

  • 活跃会话陡增
  • ECS底层资源争抢(非独享型实例)
  • 慢SQL被大量执行

三种可能性有对应的排查方法,如下图所示:

图1 排查思路

排查方法

  • 活跃连接数陡增排查方法

    活跃连接数陡增会有两个比较典型的现象:内核态CPU时间占比>20%,活跃连接数会有陡增的情况,可以结合起来一起看。

    • 查看内核态CPU时间占比

      通过管理控制台中的监控平台中内核态CPU时间占比监控项进行查看,选择近1小时查看当前的内核态CPU时间占比。

      若内核态CPU时间占比高于​20%​,此时说明可能存在大量的系统调用或者中断,通常对应的是系统中存在大量正在工作的进程。

      当活跃连接数超出了实例规格的承受能力,系统不停的切换CPU中运行的进程,而内核程序切换CPU让其在不同的地址空间上操作,导致内核态CPU时间占比升高。

    • 查看活跃连接数

      通过管理控制台中的监控平台中的活跃连接数监控项进行查看,选择近24小时或近7天查看最近一段时间的活跃连接数的情况,确认是否存在陡增现象以及陡增时间点。

      正常情况下,合理的活跃会话数量应当是当前CPU核数的2倍,此时的CPU使用效率最高。

  • ECS资源争抢(非独享型实例)

    在内核态CPU时间占比>20%的场景中,还有一种比较罕见的情况:​ECS资源争抢​,这种情况发生在非独享型(包括:通用型、通用增强型等)实例中。

    通常情况下,RDS for PostgreSQL实例上的内核态CPU都是低于10%的,当内核态CPU时间占比>10%以上就要警惕是否是由ECS资源争抢导致的CPU爆满,可以联系客服确认是否发生资源争抢。

  • 导致CPU消耗陡增的SQL排查方法

    华为云RDS for PostgreSQL数据库有慢SQL日志,可以通过这个日志,定位到当时比较耗时的SQL来进一步做分析。但通常问题发生时,整个系统都处于停滞状态,所有SQL都慢下来,当时记录的慢SQL可能非常多,并不容易找到目标。

    这里推荐几种追查慢SQL的方法,除了慢SQL以外,还有一些简单执行时间很短的SQL,在某些情况下(例如:在事务中循环执行、大量的并发执行)也会导致CPU消耗的陡增。

    追查慢SQL方法如下:

    1. 通过pg_stat_statements插件定位导致CPU消耗增高的SQL,详细使用请参考使用pg_stat_statements插件
    2. 通过pg_stat_activity视图查看当前长时间执行的SQL。

      可通过如下SQL获取可能造成CPU过高的SQL:

      SELECT  *,    
      (now() - backend_start) AS proc_duration,    
      (now() - xact_start) AS xact_duration,  
       (now() - query_start) AS query_duration,   
       (now() - state_change) AS state_duration  
      FROM pg_stat_activity  
       WHERE pid<>pg_backend_pid()  
      ORDER BY state_duration DESC limit 10;
    3. 通过查询pg_stat_user_tables,排查数据库中存在的大量的全表扫描的表以及对应的SQL。

      执行如下SQL获取存在大量全表扫描的表:

      select * from pg_stat_user_tables order by seq_tup_read desc, seq_scan desc limit 10;
    4. 结合pg_stat_statements或者pg_stat_activity,排查是否存在对应的慢SQL。

      前提需要安装pg_stat_statements插件。

      结合pg_stat_statements排查慢SQL:

      select * from pg_stat_statements where query like '%tablename%' order by shared_blks_hit + shared_blks_read desc;

      结合pg_stat_activity排查慢SQL:

      select 
        *, 
        (now() - backend_start) AS proc_duration,
        (now() - xact_start) AS xact_duration,
        (now() - query_start) AS query_duration,
        (now() - state_change) AS state_duration 
      from pg_stat_activity
      where pid<>pg_backend_pid() and query like '%tablename%'
      ORDER BY state_duration DESC;

      这些慢SQL通常是由于缺少查询对应的索引,导致过多的buffer读,从而消耗大量CPU。

解决方法

  • 活跃连接数陡增

    从业务侧确认陡增活跃连接数是否是业务所需,若为业务所需建议通过提高实例规格来解决问题,否则从业务上优化活跃连接数陡增问题。

  • ECS资源争抢(非独享型实例)

    如果确认是ECS资源争抢,建议转为独享型实例。

  • 慢SQL被大量执行

    定位到导致CPU消耗增加的SQL,对SQL进行优化。