当遇到 I/O 性能问题时,可以使用 iostat、iotop、 blktrace 等工具分析磁盘 I/O 的瓶颈。
查看/proc/<pid>/下的的meminfo、status等文件可以具体才看到虚拟内存和实际物理内存 的使用情况。
查看cpu个数:grep 'model name' /proc/cpuinfo | wc -l
使用 uptime 命令查看三个不同时间间隔的平均值,如果 1 分钟、5 分钟、15 分钟的三个值基本相同,或者相差不大,那就说明系统负载很平稳。
案例
基于 Ubuntu 18.04,预先安装 stress 和 sysstat 包
apt install stress sysstat
sudo apt install stress
场景一:CPU 密集型进程
运行 stress 命令,模拟一个 CPU 使用率 100% 的场景:
在一个终端执行:stress --cpu 1 --timeout 600
在另一个终端执行:watch -d uptime
在第三个终端运行 mpstat 查看 CPU 使用率的变化情况:
# -P ALL 表示监控所有 CPU,后面数字 5 表示间隔 5 秒后输出一组数据
root@davinci-mini:/home/HwHiAiUser# mpstat -P ALL 5
Linux 4.19.90+ (davinci-mini) 12/23/21 _aarch64_ (8 CPU)
18:28:02 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
18:28:07 all 13.48 0.00 3.14 0.05 0.00 0.05 0.00 0.00 0.00 83.27
18:28:07 0 19.18 0.00 2.45 0.00 0.00 0.20 0.00 0.00 0.00 78.16
18:28:07 1 18.53 0.00 3.67 0.00 0.00 0.00 0.00 0.00 0.00 77.80
18:28:07 2 20.69 0.00 5.07 0.00 0.00 0.00 0.00 0.00 0.00 74.24
18:28:07 3 19.31 0.00 4.88 0.00 0.00 0.00 0.00 0.00 0.00 75.81
18:28:07 4 15.31 0.00 4.29 0.00 0.00 0.20 0.00 0.00 0.00 80.20
18:28:07 5 15.27 0.00 4.68 0.41 0.00 0.20 0.00 0.00 0.00 79.43
18:28:07 6 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
18:28:07 7 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
查看哪个进程导致了 CPU 使用率高,可以使用 pidstat 来查询:
# 间隔 5 秒后输出一组数据
root@davinci-mini:/home/HwHiAiUser# pidstat -u 5 1
Linux 4.19.90+ (davinci-mini) 12/23/21 _aarch64_ (8 CPU)
18:30:20 UID PID %usr %system %guest %wait %CPU CPU Command
18:30:25 0 10 0.00 0.20 0.00 0.00 0.20 3 rcu_sched
18:30:25 0 1007 0.20 0.00 0.00 0.00 0.20 0 systemd-journal
18:30:25 100 1370 0.00 0.20 0.00 0.00 0.20 0 systemd-network
18:30:25 0 1883 0.00 0.20 0.00 0.00 0.20 2 drvlog_work_0
18:30:25 1000 2207 0.00 0.20 0.00 0.00 0.20 0 dmp_daemon
18:30:25 0 2352 2.59 1.59 0.00 0.00 4.18 5 analyzer
18:30:25 0 2406 0.20 0.00 0.00 0.00 0.20 3 alertmanager
18:30:25 0 2709 0.00 0.20 0.00 0.00 0.20 5 npu-smi
18:30:25 0 8552 0.20 0.40 0.00 0.00 0.60 1 pidstat
18:30:25 0 10352 0.00 0.20 0.00 0.00 0.20 5 kworker/5:1H-kblockd
18:30:25 0 12070 8.37 0.80 0.00 0.00 9.16 2 java
18:30:25 0 14614 0.20 1.20 0.00 0.00 1.39 4 stream
18:30:25 0 24877 0.00 0.20 0.00 0.00 0.20 0 kworker/0:2-events
18:30:25 0 25422 93.43 20.32 0.00 0.00 100.00 3 vmr-lite
场景二:I/O 密集型进程
运行 stress 命令,但这次模拟 I/O 压力,即不停地执行 sync:
在一个终端执行:stress -i 1 --timeout 600
在第二个终端运行 uptime 查看平均负载的变化情况:watch -d uptime
第三个终端运行 mpstat 查看 CPU 使用率的变化情况:
# 显示所有 CPU 的指标,并在间隔 5 秒输出一组数据
mpstat -P ALL 5 1
可以看到iowait导致平均负载升高
哪个进程,导致 iowait 这么高呢?我们还是用 pidstat 来查询:
# 间隔 5 秒后输出一组数据,-u 表示 CPU 指标
pidstat -u 5 1
可以发现,是 stress 进程导致的。
场景三:大量进程的场景
当系统中运行进程超出 CPU 运行能力时,就会出现等待 CPU 的进程。
我们使用 stress,但这次模拟的是 8 个进程: stress -c 8 --timeout 600
由于系统只有 2 个 CPU,明显比 8 个进程要少得多,因而,系统的 CPU 处于严重过载状态, 平均负载高达 7.97:
uptime
..., load average: 7.97, 5.93, 3.02
接着再运行 pidstat 来看一下进程的情况:
# 间隔 5 秒后输出一组数据,-u 表示 CPU 指标
pidstat -u 5 1
8 个进程在争抢 2 个 CPU,每个进程等待 CPU 的时间(也就是代码块中的 %wait 列)高达 75%。这些超出 CPU 计算能力的进程,最终导致 CPU 过载。
小结
平均负载高有可能是 CPU 密集型进程导致的;
平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O 更繁忙了;
当发现负载高的时候,你可以使用 mpstat、pidstat 等工具,辅助分析负载的来源。
上下文切换导致负载高
vmstat是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU 上下文切换和中断的次数。
HwHiAiUser@davinci-mini:~$ vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 2297856 1048880 1900820 0 0 1 18 2 0 19 4 77 0 0
3 0 0 2344436 1048880 1900856 0 0 0 85 25325 50968 22 5 74 0 0
6 0 0 2424336 1048888 1900860 0 0 0 160 25343 49313 15 4 81 0 0
2 0 0 2433636 1048888 1900868 0 0 0 100 24543 48054 23 4 72 0 0
3 0 0 2437372 1048888 1900880 0 0 0 95 23893 48505 21 4 75 0 0
cs(context switch)是每秒上下文切换的次数。
in(interrupt)则是每秒中断的次数。
r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数。
b(Blocked)则是处于不可中断睡眠状态的进程数。
vmstat 只给出了系统总体的上下文切换情况,要想查看每个进程的详细情况,就需要使用我们 前面提到过的 pidstat 了。给它加上 -w 选项,你就可以查看每个进程上下文切换的情况了。
HwHiAiUser@davinci-mini:~$ pidstat -w 5
Linux 4.19.90+ (davinci-mini) 12/23/21 _aarch64_ (8 CPU)
18:57:58 UID PID cswch/s nvcswch/s Command
18:58:03 0 1 0.20 0.00 systemd
18:58:03 0 9 10.76 0.80 ksoftirqd/0
18:58:03 0 10 113.55 0.00 rcu_sched
18:58:03 0 12 0.40 0.00 migration/0
18:58:03 0 15 0.40 0.00 migration/1
18:58:03 0 16 0.40 0.00 ksoftirqd/1
这个结果中有两列内容是我们的重点关注对象。
一个是 cswch ,表示每秒自愿上下文切换 (voluntary context switches)的次数。
另一个则是 nvcswch ,表示每秒非自愿上下文切换 (non voluntary context switches)的次数。
案例
使用 sysbench 来模拟系统多线程调度切换的情况,预先安装 sysbench 和 sysstat 包,如 apt install sysbench sysstat
在第一个终端里运行 sysbench ,模拟系统多线程调度的瓶颈:
# 以 10 个线程运行 5 分钟的基准测试,模拟多线程切换的问题
sysbench --threads=10 --max-time=300 threads run
在第二个终端运行 vmstat ,观察上下文切换情况:
# 每隔 1 秒输出 1 组数据(需要 Ctrl+C 才结束)
$ vmstat 1
你应该可以发现,cs 列的上下文切换次数从之前的 35 骤然上升到了 139 万。同时,注意观察 其他几个指标:
r 列:就绪队列的长度已经到了 8,远远超过了系统 CPU 的个数 2,所以肯定会有大量的 CPU 竞争。
us(user)和 sy(system)列:这两列的 CPU 使用率加起来上升到了 100%,其中系统 CPU 使用率,也就是 sy 列高达 84%,说明 CPU 主要是被内核占用了。
in 列:中断次数也上升到了 1 万左右,说明中断处理也是个潜在的问题。
综合这几个指标,我们可以知道,系统的就绪队列过长,也就是正在运行和等待 CPU 的进程数过多,导致了大量的上下文切换,而上下文切换又导致了系统 CPU 的占用率升高。
那么到底是什么进程导致了这些问题呢?
在第三个终端再用 pidstat 来看一下, CPU 和进程上下文切换的情况:
# -w 参数表示输出进程切换指标,而 -u 参数则表示输出 CPU 使用指标
# -wt 参数表示输出线程的上下文切换指标
HwHiAiUser@davinci-mini:~$ pidstat -w -u 1
Linux 4.19.90+ (davinci-mini) 12/23/21 _aarch64_ (8 CPU)
19:05:01 UID PID %usr %system %guest %wait %CPU CPU Command
19:05:02 0 10 0.00 0.98 0.00 0.00 0.98 1 rcu_sched
19:05:02 0 1483 0.98 0.00 0.00 0.00 0.98 3 prometheus
19:05:02 0 1904 5.88 0.00 0.00 0.00 5.88 1 java
19:05:02 0 2452 1.96 2.94 0.00 0.00 4.90 1 stream
19:05:02 0 21148 82.35 22.55 0.00 0.00 100.00 5 vmr-lite
19:05:02 0 22155 99.02 11.76 0.00 0.00 100.00 1 analyzer
19:05:02 1000 23640 0.98 0.98 0.00 0.00 1.96 3 pidstat
中断
从 /proc/interrupts 这个只读文件中读取。/proc 实际上是 Linux 的一个虚拟文 件系统,用于内核空间与用户空间之间的通信。/proc/interrupts 就是这种通信机制的一部分, 提供了一个只读的中断使用情况。
# -d 参数表示高亮显示变化的区域
$ watch -d cat /proc/interrupts
小结:
首先通过uptime查看系统负载,然后使用mpstat结合pidstat来初步判断到底 是cpu计算量大还是进程争抢过大或者是io过多,接着使用vmstat分析切换次数,以及切换 类型,来进一步判断到底是io过多导致问题还是进程争抢激烈导致问题。
# 并发 10 个请求测试 Nginx 性能,总共测试 100 个请求
$ ab -c 10 -n 100 http://192.168.0.10:10000/