写在前面:
由于之前在开发分布式系统中由于云服务器性能原因,导致系统总是断连等错误。但是之前一般只是简单gdb调试一下,定位错误异常艰难,所以决定开设此专栏,系统的记录我学习Linux 性能优化的历程。

作者邮箱:2107810343@qq.com
时间:2021/04/29 13:46
实现环境:Linux
系统:ubuntu 18.04

CPU使用率的定义

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使用率:
在这里插入图片描述

查看CPU使用率:top和pidstat

现在,我们来使用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使用率

排查高CPU使用率:pref

我们刚刚在这幅图也看到了,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性能优化实战.极客时间
Logo

更多推荐