load高但是cpu占用率低的排查

CPU不高的情况,一遍cpu的wait或idle都有较大的值,表明CPU利用率不高

1. 一种情况是磁盘IO过高,导致线程等待

使用vmstat 命令,查看io的情况。
vmstat 2 5

或使用iotop工具,默认显示对IO高低进行倒序实时显示,其中tid即是pid

Ubuntu:apt-get install iotop -y

2. 另一种情况,比较复杂,可能是运行的应用线程频繁切换导致

load 呈现的是CPU等待处理的请求队列的压力,load太高表明有太多请求等待处理

参考 https://www.isolves.com/it/wl/js/2020-06-01/19173.html,下面摘录部分,更多见原文

排查导致load高的原因
tips:系统load高,不代表cpu资源不足。Load高只是代表需要运行的队列累计过多。但队列中的任务实际可能是耗cpu的,也可能是耗i/0及其他因素的

vmstat 2 5
查看系统整体运行状态
io的bi(block in)--bo(block out)列,表示I/O状态。
system的中断数(in)、上下文切换(cs)特别频繁,进程上下文切换次数较多的情况下,很容易导致CPU将大量的时间耗费在寄存器、内核栈、以及虚拟内存等资源的保存和恢复上,进而缩短了真正运行进程的时间造成load高。

CPU寄存器,是CPU内置的容量小、但速度极快的内存。程序计数器,则是用来存储CPU正在执行的指令的位置,或者即将执行的下一条指令的位置。
他们都是CPU在运行任何任务前,必须依赖的环境,因此也被叫做CPU上下文。

CPU上下文切换,就是先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文,到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

排查大方向:频繁的中断以及线程切换(由于该台ecs上只存在一个JAVA服务,主要排查该进程)

通过vmstate只能查看总的cpu上下文切换,可通过pidstat命令查看线程层面的上下文切换信息 pidstat -wt 1 (1表示每1秒刷新一次)

如运行Java服务:
第一个是java线程特别多
第二个是很有规律的出现每秒上下文切换100+次的线程。
确认一下这些java线程的来源,查看该应用进程下的线程数
cat /proc/17207/status
线程数9749(非高峰)

排查方向:
线程数过多
部分线程每秒上下文切换次数过高
先排查主要原因,即部分线程上下文切换次数过高 拉一下线上该进程的堆栈信息,然后找到切换次数达到100+/每秒的线程id,把线程id转成16进制后在堆栈日志中检索

其他参考:
https://www.cnblogs.com/lddbupt/p/5779655.html

cpu load高的排查思路
1. 首先排查哪些进程cpu占用率高。 通过命令 ps ux
image

2. 查看对应java进程的每个线程的CPU占用率。通过命令:ps -Lp 15047 cu
image

3. 追踪线程内部,查看load过高原因。通过命令:jstack 15047。
或者打印线程 jstack pidof java > stack.out

查找到对应的threadid, 再反查代码。

一般经验
cpu load的飙升,一方面可能和full gc的次数增大有关,一方面可能和死循环有关系

数据库系统load高的一般原因
1 业务并发调用全表扫描/带有order by 排序的SQL语句.
2 SQL语句没有合适索引/执行计划出错/update/delete where扫描全表,阻塞其他访问相同表的sql执行.
3 存在秒杀类似的业务比如聚划算10点开团或者双十一秒杀,瞬时海量访问给数据库带来冲击。
4 数据库做逻辑备份(需要全表扫描)或者多实例的压缩备份(压缩时需要大量的cpu计算,会导致系统服务器load飙高)
5 磁盘写入方式改变 比如有writeback 变为 write through
RAID卡都有写cache(Battery Backed Write Cache),写cache对IO性能的提升非常明显,因为掉电会丢失数据,所以必须由电池提供支持。
电池会定期充放电,一般为90天左右,当发现电量低于某个阀值时,会将写cache策略从writeback置为writethrough,相当于写cache会失效,这时如果系统有大量的IO操作,可能会明显感觉到IO响应速度变慢,cpu 队列堆积系统load 飙高。

判别和处理load高问题
一般根据cpu数量去判断,也就是Load平均要小于CPU的数量,负载的正常值在不同的系统中有着很大的差别。在单核处理器的工作站中,1或2都是可以接受的。多核处理器的服务器(比如24核)上,load 会到达20 ,甚至更高。

a) 数据库层面
1 top -u mysql -c 检查当前占用cpu资源最多的进程命令。-c是为了显示出进程对应的执行命令语句,方便查看是什么操作导致系统load飙高。
2 根据不同的情况获取pid 或者MySQL的端口号
3 如果是MySQL 数据库服务导致laod 飙高,则可以使用如下命令
show processlist;
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND <> 'sleep' AND TIME>100;

orzdba 工具检查逻辑读/thread active的值。用法:orzdba --help
orztop 工具检查当前正在执行的慢sql,用法:orztop -P $port
4 获取异常的sql之后,剩下的比较好解决了。结合第一部分中的几条原因
a 选择合适的索引
b 调整sql语句 比如对应order by分页采用延迟关联
c 业务层面增加缓存,减少对数据库的直接访问等
b) OS 系统层面 检查系统IO
使用iostat -x命令查看r/s(读请求)、w/s(写请求)、avgrq-sz(平均请求大小)、await(IO等待)、svctm(IO响应时间)
r/s、w/s是每秒读/写请求的次数。

util是设备的利用率。如果它接近100%,通常说明设备能力趋于饱和(并不绝对,比如设备有写缓存)。有时候可能会出现大于100%的情况,这多半是计算时四舍五入引起的。
svctm是平均每次请求的服务时间。这里有一个公式:(r/s+w/s)*(svctm/1000)=util。举例子:如果util达到100%,那么此时svctm=1000/(r/s+w/s),假设IOPS是1000,则svctm大概在1毫秒左右,如果长时间大于这个数值,说明系统出了问题。
await是平均每次请求的等待时间。这个时间包括了队列时间和服务时间,也就是说,一般情况下,await大于svctm,它们的差值越小,队列时间越短,反之差值越大,队列时间越长,说明系统出了问题。
avgqu-sz是平均请求队列的长度。毫无疑问,队列长度越短越好。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章