写在前面:
由于之前在开发分布式系统中由于云服务器性能原因,导致系统总是断连等错误。但是之前一般只是简单gdb调试一下,定位错误异常艰难,所以决定开设此专栏,系统的记录我学习Linux 性能优化的历程。
作者邮箱:[email protected]
时间:2021/04/29 13:46
实现环境:Linux
系统:ubuntu 18.04
CPU使用率是一个衡量当前CPU瓶颈的重要指标。我们首先就需要知道CPU使用率是怎么计算出来的。
为了维护CPU时间,Linux会事先定义节拍率(内核表示HZ),触发时间中断,并维护全局变量Jiffies
记录了开机以来的节拍数。每发生一次时间中断,Jiffies
的值就加一。
注:
这也是CPU时间片轮转法实施的基础。
节拍数是内核的可配置选项,可以设置为100、250、1000等。不同的系统可能设置不同数值,可以通过查看/boot/config内核选项来查看它的配置值。
ubuntu@VM-0-2-ubuntu:~/ByteTalk/UserService$ grep 'CONFIG_HZ=' /boot/config-$(uname -r)
CONFIG_HZ=250
# 我这里设置就是250HZ,也就是4ms切换一次
Linux通过 /proc 虚拟文件系统,向用户空间提供系统内部状态信息,而/proc/stat提供的就是系统的CPU 和任务统级时间。
# 保留CPU的数据
ubuntu@VM-0-2-ubuntu:~/ByteTalk/UserService$ cat /proc/stat | grep ^cpu
cpu 15517599 934 269286 18794245 70312 0 3441 0 0 0
cpu0 11026589 293 105096 6155651 46206 0 1590 0 0 0
cpu1 4491010 640 164189 12638593 24106 0 1850 0 0 0
第一行时两个CPU各个时间的总和,以下是各个列的解释:
列名 | 含义 |
---|---|
cpu | 表示CPU编号,如cpu0,cpu1 |
user | 代表用户态的CPU时间,不包括nice和guest时间 |
nice | 待避岙低优先级用户态CPU时间,也就是进程的nice值被调整为1-19之间时的CPU时间 |
system | 内核态CPU时间 |
idle | 代表空闲时间,不包括等待I/O时间 |
iowait | 等待I/O的CPU时间 |
irq | 硬中断的CPU时间 |
softtrip | 软中断的CPU时间 |
steal | 代表当前系统运行在虚拟机中的时候,被其他虚拟机占用的CPU时间 |
guest | 通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的CPU时间 |
guest_nice | 以低优先级运行虚拟机的时间 |
而CPU使用率,就是除了空闲时间外其他时间占总CPU时间的百分比:
但是这个公式是有缺陷的,/proc/stat里面统计的是开机以来的数据,我们真正需要的是瞬时值,所以公式就应该做个修改,每隔几秒取以下值,两次间隔中取差值去计算CPU使用率:
现在,我们来使用top查看一下CPU的使用率:
ubuntu@VM-0-2-ubuntu:~/ByteTalk/UserService$ top
在这个结果中,第三行就是CPU使用率了。然后下面白色行之后就是每个进程的情况,都有一个%CPU列,表示进程的CPU使用率。它是用户态和内核态CPU使用率的总和,包括进程用户空间使用的CPU、通过系统调用执行的内核空间CPU以及在就绪队列中等待运行的CPU。
但是top,没有具体解决如何查看用户态和内核态CPU使用率的问题,我们就需要使用pidstat来查看一下。
# 每秒输出一次数据,总共输出3组
ubuntu@VM-0-2-ubuntu:~/ByteTalk/UserService$ pidstat 1 3
列名 | 含义 |
---|---|
%user | 用户态CPU使用率 |
%system | 内核态CPU使用率 |
%guest | 运行虚拟机CPU使用率 |
%wait | 等待CPU使用率 |
%cpu | 总CPU使用率 |
我们刚刚在这幅图也看到了,node进程占用了非常高的CPU使用率,由于不是作者自己写的进程,我只能尝试着排查,给大家演示一下:
调试的话,熟悉Linux开发的小伙伴肯定第一时间想到的就是gdb调试了,但是gdb调试并不适合性能分析的早期应用。因为gdb调试程序的过程会中断程序运行,这在线上环境往往是不允许的。
我们现在来使用工具perf来分析CPU性能问题:
先安装一下perf吧:
ubuntu@VM-0-2-ubuntu:~/ByteTalk/UserService$ sudo apt install linux-tools-common
ubuntu@VM-0-2-ubuntu:~/ByteTalk/UserService$ sudo apt install linux-tools-generic
ubuntu@VM-0-2-ubuntu:~/ByteTalk/UserService$ sudo apt install linux-tools-4.15.0-140-generic
然后执行以下命令:
# 这个可以像top那样,实时显示占用CPU时钟最多的函数或者指令,因此可以查找热点函数
ubuntu@VM-0-2-ubuntu:~/ByteTalk/UserService$ perf top
第一行有三个数据:采样数(samples)、事件类型(event)和事件总数量(event count)
它的输出结果分别包括四种数据:
列名 | 含义 |
---|---|
overhead | 该符号的性能事件在所有采样中的比例 |
shared | 该函数或指令所在动态库共享对象 |
object | 共享对象的类型,[.]表示用户空间的可执行程序,或者动态连接库,[k]表示内核空间 |
symbol | 函数名,当函数名未知的时候,用16进制的地址来表示 |
这里我们可以看到是node进程里面的某个函数(具体看图)造成的CPU高使用率。
注:
node是nodejs,是vscode中插件的依赖,可以直接kill
另外,由于perf top是实时查看CPU使用情况的,但是不会保存数据,也就无法用于离线或者后续的分析,我们就需要使用使用 perf record 和 perf report 了:
# 开启后自动捕捉数据,按ctrl+c结束采样
ubuntu@VM-0-2-ubuntu:~/ByteTalk/UserService$ sudo perf record
^C[ perf record: Woken up 5 times to write data ]
[ perf record: Captured and wrote 1.443 MB perf.data (24504 samples) ]
# 展示采样的数据
ubuntu@VM-0-2-ubuntu:~/ByteTalk/UserService$ sudo perf report
注:
这个采样百分比和某进程是否占用过高的CPU资源是无关的!
[1] 倪朋飞.Linux性能优化实战.极客时间