在实际的开发工作中,常见的描述系统CPU性能的方式,不是平均负载,不是CPU上下文切换,而是CPU使用率这种方式

CPU使用率是单位时间内CPU使用的统计,使用百分比进行统计,我们今天就对常见的CPU统计指标进行讲解,常见的有, %user %nice %system %iowait %steal

Linux作为一个多任务操作系统,将每个CPU的时间分为了很短的时间,通过调度器轮流分配不同的任务使用,多任务同时进行的错觉

为了维护Cpu的时间片,Linux通过事先定义的节拍率,触发时间中断,使用全局变量 jiffies记录了开机以来的节拍数,每触发一次时间中断,Jiffies就加一

节拍率是可以配置的,可设置位 100 250 1000等,设置的数值在 boot/config内核中查看,基本如下

$ grep ‘CONFIG_HZ=’ /boot/config-$(uname -r)

CONFIG_HZ=250

节拍率设置位250,每秒触发250次时间中断

在之后因为节拍率是内核选项,所以用户空间程序不能直接的访问,用户空间有自己的节拍率 USER_HZ,固定为100,1/100秒中断一次

Linux通过 /proc虚拟文件系统,让用户可以查看系统内部运行状态,/proc/stat提供的就是系统CPU和任务的统计信息

查看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的总和,其他的都是以USER_HZ为单位,不同情景下的累加节拍数

接下来,每列的指标如下

user 用户态cpu时间

nice 低优先级时间,user中不计算本时间,nice取值范围是-20到19,进程的nice值被调整为这个区间内的CPU时间

system 内核态CPU时间

idle 空闲时间,不包括等待IO的时间

iowait 等待io的时间

irq 处理硬中断的CPU的时间

softirq 软中断的CPU时间

steal,系统运行在虚拟机的时候,被其他虚拟机占用时间

guest 运行虚拟机的CPU时间

guest_nice 低优先级运行虚拟机的时间

CPU使用率,就是空闲时间外的其他时间占CPU总时间的比

图片

据此

我们就可以从/proc/stat中数据,很容易的计算出CPU的使用率,

但是/proc/stat的数据,计算的是开机以来这一个时间戳的CPU使用率

如果需要计算更加细粒度的CPU使用率,可能使用一些常见的性能计算工具

一般这种性能计算工具,计算方式如下

图片

对应的进程级别的指标,也可以通过 /proc/[pid]/stat

还有就是,注意不同的性能工具间的查询时间间隔,比如top和ps的CPU使用率,时间间隔就不一样

top默认3秒,ps是整个进程声明周期

我们分别那这两个性能分析工具,进行查看CPU使用率

top的输出格式如下,系统总体的CPU和内存的使用情况,各个进程资源的使用情况

# 默认每3秒刷新一次

$ top

top – 11:58:59 up 9 days, 22:47,  1 user,  load average: 0.03, 0.02, 0.00

Tasks: 123 total,   1 running,  72 sleeping,   0 stopped,   0 zombie

%Cpu(s):  0.3 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

KiB Mem :  8169348 total,  5606884 free,   334640 used,  2227824 buff/cache

KiB Swap:        0 total,        0 free,        0 used.  7497908 avail Mem

PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND

1 root      20   0   78088   9288   6696 S   0.0  0.1   0:16.83 systemd

2 root      20   0       0      0      0 S   0.0  0.0   0:00.05 kthreadd

4 root       0 -20       0      0      0 I   0.0  0.0   0:00.00 kworker/0:0H

第三列 %CPU就是系统CPU的使用率,不过top,显示的是所有CPU的平均值,如果按下数字1,就切换为每个CPU使用率

然后每个进程PID后面的类,都显示了自己的CPU使用,是说明的用户态和内核态CPU使用率的综合,包含了进程用户空间使用的CPU,虚拟化环境中,还包括了运行虚拟机占用的CPU

top没有细分进程用户态CPU和内核态CPU,如果想要更加详细的查看,需要使用对应的pidstat,一个专门分析每个进程CPU使用情况的工具

pidstat可以查看常见的CPU使用率

用户态CPU 使用率 %user

内核态CPU使用率 %system

运行虚拟机CPU使用率%guest

等待CPU的使用率 %wait

最后Average部分,还计算了5组数据的平均值

# 每隔1秒输出一组数据,共输出5组

$ pidstat 1 5

15:56:02      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command

15:56:03        0     15006    0.00    0.99    0.00    0.00    0.99     1  dockerd

Average:      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command

Average:        0     15006    0.00    0.99    0.00    0.00    0.99     –  dockerd

那么如何查看哪些CPU使用率高的进程呢?

GDB是一个程序调适的利器,但是GDB在线上环境往往不被允许,因为需要中断程序运行

常见的这类分析利器,是使用perf来进行CPU性能分析

perf top类似 top,实时显示占用的CPU最多的函数或者指针,以此来查找热点函数

perf top

图片

第一行的参数有 Samples 采样数 event 事件类型 event count 事件总数量

perf总共采集了833个CPU时钟事件,总事件数是97742399

下面的是一个表格样式的数据

包含四列

第一列 Overhead 符号性能事件在所有采样中的比例,百分比表示

第二列 Shared 该函数或者指令所在动态共享对象 内核 进程名 动态链接库名,内核模块名

第三列 Object 动态共享对象的类型

第四列 Symbol 符号名,函数名,未知的话,以十六进制地址表示

上面看出,占用CPU时间最多的是perf工具本身,但是只有7.28%,说明CPU没有性能问题

然后第二种用法,perf recod 和 perf report

将性能信息保存起来,用于后续的分析

record用于保存数据,report用于解析并展示数据

perf record进行采样

perf report用于报告

那么我们演示一下 top加上perf进行配合查看系统问题的方式

使用两个镜像进行演示

一个PHP应用,一个NGINX

我们将这两个镜像进行部署在一个服务器上

然后另一台进行发送请求测试

我们尝试使用ab压力测试工具来进行测试

ab -c 10 -n 100 http://192.168.0.10:10000/

10个线程 100次

最后返回结果如下

图片

每秒的平均次数是11.63,很拉胯

那么我们在发送请求的时候,进行尝试查看问题

首先是继续发送

ab -c 10 -n 10000 http://192.168.0.10:10000/

然后在第一个终端

运行top命令

利用数字1查看每个CPU的使用率

这样,我们可以看到,系统中几个php-fpm 进程的CPU使用率加起来接近200%,而每个CPU的使用率us超过了98%,接近饱和,这样,就可以确认使用php-fpm进程,导致CPU使用率升高

如何确定是哪个函数导致的呢?

使用perf来看一下

perf top -g -p xxxxx

查看对应的函数

图片

查看到对应的函数是sqrt和add_function

这样,就可以从这两个函数入手了

对应的源码中,可以查看到对应的调用方式,并进行修复了

本章小结一下:

CPU使用率是最常用和直观的系统性能指标,查看性能问题的时候,关注的一个指标就这个指标,常见的CPU的指标有 %user %nice %system %iowait %irq %softirq

用户CPU和Nice CPU高,说明用户态占用了比较多的CPU,排查进程的性能问题

系统CPU高,说明内核态占用较多的CPU,排查内核线程或者系统调用的性能问题

IO等待CPU高,是说明IO时间长,排查系统存储的问题

软中断或硬中断高,说明软中断或者硬中断的处理程序占用较高CPU,排查内核的中断程序

CPU高的问题,利用top或者pidstat等工具,确认引发的来源,使用perf工具,排查出引起性能的具体函数

发表评论

邮箱地址不会被公开。 必填项已用*标注