四. 性能优化之基础篇: 某个应用的CPU使用率居然达到100%,我该怎么办?

本文深入讲解Linux系统下CPU性能分析,涵盖节拍器HZ、Jiffies、USER_HZ概念,/proc/stat文件解读,以及使用top、ps、pidstat、perf等工具分析CPU使用率,特别介绍了perf工具的高级用法,如perftop实时展示和perfrecord采样分析。

基础概念

节拍器HZ
  1. 节拍器HZ定义每秒钟触发时间中断的次数
  2. 节拍器HZ为内核的可配选项,可以设置为 100、250、1000等。不同的系统可能设置不同数值
  3. 可以通过查询/boot/config内核选项来查看它的配置值,如命令 grep ‘CONFIG_HZ=’ /boot/config-$(uname -r)查看系统定义的节拍器
Jiffies

Jiffies是一个全局变量记录了开机以来的节拍数。每发生一次时间中断,Jiffies 的值就加 1。

USER_HZ
  1. 内核给用户空间定义的节拍器(节拍率 HZ 是内核选项,所以用户空间程序并不能直接访问)
  2. 固定为100,这样用户空间并不需要关心内核中 HZ 被设置成了多少,因为它看到的总是固定值 USER_HZ
/proc/stat
  • 可以通过/proc/stat文件查看系统的 CPU 和任务统计信息
# 只保留各个CPU的数据
$ cat /proc/stat | grep ^cpu
cpu  280580 7407 286084 172900810 83602 0 583 0 0 0
cpu0 144745 4181 176701 86423902 52076 0 301 0 0 0
cpu1 135834 3226 109383 86476907 31525 0 282 0 0 0

第一列表示的是 CPU 编号,如 cpu0、cpu1 ,而第一行没有编号的 cpu ,表示的是所有 CPU 的累加。其他列则表示不同场景下 CPU 的累加节拍数,它的单位是 USER_HZ,也就是 10 ms(1/100 秒),所以这其实就是不同场景下的 CPU 时间

  • 每一列指标的含义
user(通常缩写为 us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。
nice(通常缩写为 ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。
system(通常缩写为 sys),代表内核态 CPU 时间。
idle(通常缩写为 id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait)。
iowait(通常缩写为 wa),代表等待 I/O 的 CPU 时间。
irq(通常缩写为 hi),代表处理硬中断的 CPU 时间。
softirq(通常缩写为 si),代表处理软中断的 CPU 时间。
steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间。
guest(通常缩写为 guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间。
guest_nice(通常缩写为 gnice),代表以低优先级运行虚拟机的时间。
CPU 使用率

除了空闲时间外的其他时间占总 CPU 时间的百分比
在这里插入图片描述

查看cpu使用率的工具

常用工具

可以定位到具体进程,但无法定位到程序内部的函数调用

1. top  
2. ps
3. pidstat
perf
perf top 实时展示

类似于 top,它能够实时显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数

$ perf top
Samples: 833  of event 'cpu-clock', Event count (approx.): 97742399
Overhead  Shared Object       Symbol
   7.28%  perf                [.] 0x00000000001f78a4
   4.72%  [kernel]            [k] vsnprintf
   4.32%  [kernel]            [k] module_get_kallsym
   3.65%  [kernel]            [k] _raw_spin_unlock_irqrestore
...

第一行包含三个数据,分别是采样数(Samples)、事件类型(event)和事件总数量
再往下看是一个表格式样的数据,每一行包含四列,分别是:

第一列 Overhead ,是该符号的性能事件在所有采样中的比例,用百分比来表示。
第二列 Shared ,是该函数或指令所在的动态共享对象(Dynamic Shared Object),如内核、进程名、动态链接库名、内核模块名等。
第三列 Object ,是动态共享对象的类型。比如 [.] 表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。最后一列 Symbol 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。

perf record 采样后保存到文件 和 perf report 解析展示

如下:

$ perf record # 按Ctrl+C终止采样
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.452 MB perf.data (6093 samples) ]

$ perf report # 展示类似于perf top的报告

-g 参数,开启调用关系的采样,方便我们根据调用链来分析性能问题

案例

  1. 搭建基础环境
$ docker run --name nginx -p 10000:80 -itd feisky/nginx
$ docker run --name phpfpm -itd --network container:nginx feisky/php-fpm
  1. ab命令请求
$ ab -c 10 -n 10000 http://127.0.0.1:10000/
  1. perf命令分析(另开终端)
# -g开启调用关系分析,-p指定php-fpm的进程号21515
$ perf top -g -p 21515

按方向键切换到 php-fpm,再按下回车键展开 php-fpm 的调用关系,你会发现,调用关系最终到了 sqrt 和 add_function,如下图所示:
在这里插入图片描述

  1. 将源码从docker中复制出来分析优化即可

$ docker cp phpfpm:/app .      # 从容器phpfpm中将PHP源码拷贝出来

$ grep sqrt -r app/  				# 找到了sqrt调用    
app/index.php:  $x += sqrt($x);

$ grep add_function -r app/ 		# 没找到add_function调用,这其实是PHP内置函数

总结

  1. 用户 CPU 和 Nice CPU 高,说明用户态进程占用了较多的 CPU,所以应该着重排查进程的性能问题。
  2. 系统 CPU 高,说明内核态占用了较多的 CPU,所以应该着重排查内核线程或者系统调用的性能问题。
  3. I/O 等待 CPU 高,说明等待 I/O 的时间比较长,所以应该着重排查系统存储是不是出现了 I/O 问题。
  4. 软中断和硬中断高,说明软中断或硬中断的处理程序占用了较多的CPU,所以应该着重排查内核中的中断服务程序。

Tips

  1. 性能分析工具给出的都是间隔一段时间的平均 CPU 使用率,所以要注意间隔时间的设置
  2. 因为运行环境在dokcer中,perf运行时并不能准确获取相关函数名称(显示为16进制),可以使用perf record命令 保存为文件,再将文件复制到docker中,在docker使用perf report进行分析
获取docker中运行函数名的方法具体步骤如下:
1. perf record  #宿主机执行生成perf.data文件
2. docker cp perf.data phpfpm:/tmp   #复制文件到运行php的docker虚拟机中
3. docker exec -i -t phpfpm bash 			#进入虚拟机
4. cd /tmp/			#移动到存放perf.data的目录下
5. apt-get update && apt-get install -y linux-perf linux-tools procps  # 安装perf
6. perf_4.9 report       #分析perf.data

运行顺利的情况下 ,可以在虚拟机中查看到具体的函数名称

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值