【RDS for PostgreSQL】CPU满问题原因及定位思路
基本概念
系统CPU使用率: 指的是整个系统CPU运行时间占总CPU时间的百分比。
CPU使用率分别有
用户态CPU时间占比
和内核态CPU时间占比
:
- 用户态: 是用户程序运行时的状态。
- 内核态: 是操作系统的管理程序运行时的状态,包含系统调用,内核线程和中断。
某个进程的CPU使用率: 就是某个进程在一段时间内占用的CPU时间占总的CPU时间的百分比。
活跃连接数: 指状态为activity
的数据库连接。
CPU核心数与活跃连接数的关系: 正常情况下,合理的活跃会话数量应当是当前CPU核数的2~3倍,例如实例规格为2核4GB时,活跃会话数应当维持在4~6个,此时的CPU使用效率最高。
问题排查思路
引起CPU爆满的原因一般分为三种:活跃会话徒增、ECS底层资源争抢(非独享型实例)、CPU消耗陡增的SQL被大量执行。三种可能性有对应的排查方法,如下图所示。
排查方法
排查步骤
第一步
:确认实例规格(CPU核心数
、内存
、规格类型
)
第二步
:查看内核态CPU时间占比
第三步
:查看活跃连接数
第四步
:判断实例规格类型
,若为独享型
则跳转至第八步
,否则下一步
第五步
:若内核态CPU时间占比
> 40%,执行下一步
,否则跳转至第八步
第六步
:与华为云ECS人员确认是否发生资源抢占
情况,若发生资源抢占
请其协助解决,然后执行下一步
,否则跳转至第八步
第七步
:等待资源抢占
情况解决后,观察CPU满问题是否得以解决,是则结束
,否则进入下一步
第八步
:查看近24小时
或者近7天
的活跃连接数监控图,判断是否有陡增情况发生,是则下一步
,否则跳转至第十二步
第九步
:与业务沟通交流最近的业务变化,识别活跃连接数陡增是否由业务变化引入,是则下一步
,否则跳转至第十二步
第十步
:分析当前活跃连接数是否超出实例规格承受范围,是则下一步
,否则跳转至第十二步
第十一步
:建议先回退业务变更,并提高数据库实例规格,待实例规格提高后再进行业务变更,结束
第十二步
:排查导致CPU消耗陡增的SQL
第十三步
:优先结束导致CPU消耗陡增的SQL的进程使业务恢复
第十四步
:观察CPU满问题是否得以解决,是则进入下一步
,否则跳转至第十六步
第十五步
:对第十二步
中获取到的导致CPU消耗陡增的SQL
进行分析、优化,彻底消除CPU爆满的隐患,结束
第十六步
:联系华为云客服,进行更深层次的问题定位。
活跃连接数陡增
活跃连接数陡增会有两个比较典型的现象:内核态CPU时间占比
>20%,活跃连接数会有陡增的情况,可以结合起来一起看。
查看内核态CPU时间占比
监控平台
通过监控平台中的内核态CPU时间占比
监控项进行查看,选择近1小时
查看当前的内核态CPU时间占比
,如下图所示。
若内核态CPU时间占比
高于20%,此时说明可能存在大量的系统调用或者中断,通常对应的是系统中存在大量正在工作的进程。
说明:
当活跃连接数超出了实例规格的承受能力,系统不停的切换CPU中运行的进程,而内核程序切换CPU让其在不同的地址空间上操作,导致
内核态CPU时间占比
升高。
查看活跃连接数
监控平台
通过监控平台中的活跃连接数
监控项进行查看,选择近24小时
或近7天
查看最近一段时间的活跃连接数
的情况,确认是否存在陡增现象以及陡增时间点,如下图所示。
另外活跃连接数
陡增与陡增时间点可以通过客户业务进一步加以确认。
小结
结合 内核态CPU时间占比
>20% 以及 活跃连接数存在陡增 现象两个现象基本可以确定CPU的爆满的原因为:活跃连接数陡增。此时可以从业务侧进行排查,确认陡增活跃连接数是否是业务所需,若为业务所需建议通过提高实例规格来解决问题,否的话则从业务上优化活跃连接数陡增问题。
ECS资源争抢(非独享型实例)
在 内核态CPU时间占比
>20% 的场景中,还有一种比较罕见的情况:ECS资源争抢,这种情况发生在非独享型(包括:通用型、通用增强型等)实例中。
当内核态CPU时间占比
>40%以上就要警惕是否是由ECS资源争抢
导致的CPU爆满,可以联系ECS员工进行确认是否发生资源争抢。
排查导致CPU消耗陡增的SQL
如果已经排除了活跃连接数陡增
、ECS资源争抢
两种可能性,那么可能是此时有慢SQL被大量执行。华为云RDS for PostgreSQL数据库有慢SQL日志,可以通过这个日志,定位到当时比较耗时的SQL来进一步做分析。但通常问题发生时,整个系统都处于停滞状态,所有SQL都慢下来,当时记录的慢SQL可能非常多,并不容易找到目标。这里推荐几种追查慢SQL的方法。除了慢SQL以外,还有一些简单执行时间很短的SQL,在某些情况下(例如:在事务中循环执行、大量的并发执行)也会导致CPU消耗的陡增。
通过以下几种方法定位到导致CPU消耗增加的SQL,可以先结束它们使业务恢复,然后再对它们进行优化。
操作行数
通过监控平台中的操作函数
监控项进行查看,选择近24小时
或者近7天
查看最近的操作行数
,如下图所示。
若最近的操作行数
出现陡增的现象,说明最近业务上可能出现了一些慢SQL,这些慢SQL通常是由于缺少查询对应的索引,导致过多的buffer读,从而消耗大量CPU。
pg_stat_statements
第一步
先查看当前数据库是否有安装pg_stat_statements
插件,执行如下SQL:
select * from pg_extension where extname = 'pg_stat_statements';
查询结果示例如下:
-- 未安装插件
xxxx=# select * from pg_extension where extname = 'pg_stat_statements';
oid | extname | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition
-----+---------+----------+--------------+----------------+------------+-----------+--------------
(0 rows)
-- 已安装插件
xxxx=# select * from pg_extension where extname = 'pg_stat_statements';
oid | extname | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition
-------+--------------------+----------+--------------+----------------+------------+-----------+--------------
xxxxx | pg_stat_statements | 34637 | 2200 | t | 1.7 | |
(1 row)
若没有安装pg_stat_statements
插件,需要手动安装一下。
第二步
为了方便排查当前CPU过高问题,需要重置pg_stat_statments
的计数器,执行以下SQL:
select pg_stat_reset();
select pg_stat_statements_reset();
然后等待一段时间,使pg_stat_statments
能够统计到足够的信息。
第三步
获取最耗时的SQL,执行一下SQL:
select * from pg_stat_statements order by total_time desc limit 10;
此步骤获取到的SQL会长时间占用用户态CPU时间
,把这些SQL取出来分析。
第四步
获取读取Buffer次数最多的SQL,执行一下SQL:
select * from pg_stat_statements order by shared_blks_hit + shared_blks_read desc limit 10;
此步骤获取到的SQL可能由于缺少查询对应的索引,导致过多的buffer读,从而消耗大量CPU。
第五步
获取执行次数最多的SQL,执行以下SQL:
select * from pg_stat_statements order by calls desc limit 10;
有些比较简单的SQL单独执行耗时较低,但是在某些情况下(例如:在事务中循环执行、大量的并发执行)也会导致CPU的消耗增高。
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;
pg_stat_user_tables
排查数据库中存在的大量的全表扫描的表以及对应的SQL。
执行一下SQL获取存在大量全表扫描的表:
select * from pg_stat_user_tables order by seq_tup_read desc, seq_scan desc limit 10;
然后结合pg_stat_statements
或者pg_stat_activity
可以查看是否存在对应的慢SQL:
-- 结合 pg_stat_statements
select * from pg_stat_statements where query like '%tablename%' order by shared_blks_hit + shared_blks_read desc;
-- 结合 pg_stat_activity
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。
- 点赞
- 收藏
- 关注作者
评论(0)