Linux 作为一个多任务操作系统,将每个 CPU 的时间划分为很短的时间片,再通过调度器轮流分配给各个任务使用,因此造成多任务同时运行的错觉。
1.CPU使用率
1.1 节拍率HZ
- Linux通过事先定义的节拍率,触发时间中断
- 使用全局变量Jiffies记录了开机以来的节拍数(中断+1)。
- 在/boot/config查看内核选项;命令:
grep 'CONFIG_HZ=' /boot/config-$(uname -r)
(目前并没找到这个文件)
1.2 /proc
Linux通过/proc虚拟文件系统,向用户空间提供了系统内部状态的信息,而/proc/stat提供的就是系统的 CPU 和任务统计信息。
1
2
3
4
5
6
7
8
|
# 只保留各个 CPU 的数据
$ cat /proc/stat | grep ^cpu
# 打印
cpu 72654 0 240530 37150942 231 0 408 0 0 0
cpu0 17980 0 58109 9280824 40 0 200 0 0 0
cpu1 18734 0 62739 9298874 67 0 81 0 0 0
cpu2 18220 0 63949 9265870 82 0 76 0 0 0
cpu3 17717 0 55731 9305373 41 0 49 0 0 0
|
每一列的涵义:
- 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),代表以低优先级运行虚拟机的时间。
1.3 CPU使用率公式
1
|
CPU使用率 = 1-(空闲时间/总CPU时间)
|
事实上,性能工具一般都会取间隔一段时间(如3s)的两次值,作差后,再计算出这段时间内的平均CPU使用率
1
|
CPU使用率 = 1-{(空闲时间new-空闲时间old)/(总CPU时间new-总CPU时间old)}
|
2.怎么查看CPU使用率
最常使用top和ps
2.1 top
top显示了系统总体的cpu和内存使用情况,以及各个进程的资源使用情况
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 默认每 3 秒刷新一次
$ top
# 打印
top - 10:12:12 up 1 day, 2:48, 0 users, load average: 0.00, 0
Tasks: 7 total, 1 running, 6 sleeping, 0 stopped, 0 zo
%Cpu(s): 0.2 us, 0.6 sy, 0.0 ni, 99.2 id, 0.0 wa, 0.0 hi,
MiB Mem : 1991.1 total, 1323.6 free, 314.2 used, 353.3
MiB Swap: 1024.0 total, 1024.0 free, 0.0 used. 1549.4
PID USER PR NI VIRT RES SHR S %CPU %MEM
1 root 20 0 4112 3276 2848 S 0.0 0.2
8 root 20 0 4112 3404 2848 S 0.0 0.2
18 root 20 0 4112 3428 2876 S 0.0 0.2
39 root 20 0 4112 3412 2860 S 0.0 0.2
75 root 20 0 4112 3420 2868 S 0.0 0.2
283 root 20 0 4236 3496 2932 S 0.0 0.2
301 root 20 0 6072 3236 2736 R 0.0 0.2
|
分析:%CPU是系统使用率,后面一排是每隔进程的CPU使用率
需要使用pidstat分析每隔进程的详情情况
1
2
3
4
5
6
7
8
|
# 每隔 1 秒输出一组数据,共输出 5 组
$ pidstat 1 5
# 打印
Linux 4.19.76-linuxkit (4f913ef1ae8f) 05/28/20 _x86_64_ (4 CPU)
...
10:22:12 UID PID %usr %system %guest %wait %CPU CPU Command
10:22:13 0 311 0.00 0.99 0.00 0.00 0.99 3 pidstat
...
|
2.2 ps
ps 则只显示了每个进程的资源使用情况。
3. CPU使用率过高怎么办?
使用perf分析CPU性能问题。它以性能事件采样为基础,不仅可以分析系统的各种事 件和内核性能,还可以用来分析指定应用程序的性能问题。
1. docker中的ubuntu中安装perf
1
2
3
4
5
6
|
# mac上docker run 要给权限
$ docker run -t -i --privileged --name ubuntu ubuntu
# 进入ubuntu容器内,安装
$ apt-get install linux-tools-generic
# 创建一个符号链接到/usr/bin/perf
$ ln -s /usr/lib/linux-tools/5.4.0-33-generic/perf /usr/bin/perf
|
1
2
3
4
5
6
7
8
9
|
$ perf top
# 打印
Samples: 85K of event 'cpu-clock:pppH', 4000 Hz, Event count (approx.): 12867561796 lost: 0/0 drop: 0/0
Overhead Shared Object Symbol
97.83% [kernel] [k] 0xffffffffa37f8223
0.35% [kernel] [k] 0xffffffffa314c746
0.34% [kernel] [k] 0xffffffffa3123a43
0.26% [kernel] [k] 0xffffffffa3108137
...
|
分析:
第一列 Overhead ,是该符号的性能事件在所有采样中的比例,用百分比来表示。
第二列 Shared ,是该函数或指令所在的动态共享对象(Dynamic Shared Object),如内核、进程名、动态链接库名、内核模块名等。
第三列 Object ,是动态共享对象的类型。比如 [.] 表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。
最后一列 Symbol是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。
4.实验
4.1 坑与环境配置
由于本地机子是macbook,无法安装perf(可能),所以在运行php-fpm时要给容器赋予主机的权限
1
|
$ docker run --privileged --name phpfpm -itd --network container:nginx feisky/php-fpm:cpu
|
在phpfpm容器内安装perf
1
|
$ apt-get install -y linux-perf
|
4.2 实验场景
- 系统的用户 CPU 使用率(usr%)过高
- 可以找出高 CPU 使用率的进程(php-fpm 进程的 CPU 使用率过高)
4.2 查找分析
- 使用
top
命令, 查看cpu使用率高的pid
- perf 分析
1
2
|
# -g 开启调用关系分析,-p 指定 php-fpm 的进程号<pid>
$ perf top -g -p <pid>
|
然后就是上下左右键,查找调用了什么系统函数导致的,再去检测代码问题