这篇文章上次修改于 899 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
1 CPU 性能指标
CPU 利用率
- 用户 CPU 利用率高,说明用户程序比较繁忙。
- 系统 CPU 利用率高,说明内核比较繁忙。
- 等待 I/O 的 CPU 使用率,即 iowait 高,说明系统与硬件的 I/O 交互时间较长。
- 软中断和硬中断的 CPU 使用率高,说明中断较多,比如 SYN 泛洪攻击导致软中断中的网络中断较多。
平均负载
- 如果平均负载大于逻辑 CPU 个数,说明负载较重。
进程上下文切换
包括无法获取资源的自愿上下文切换和被系统强制调度的非自愿上下文切换。
- 自愿上下文切换较多,可能发生了 I/O 等问题。
- 非自愿上下文切换较多,可能 CPU 成为了瓶颈。
- 过多的上下文切换会导致 CPU 时间过多地消耗在寄存器、内核堆栈、虚拟内存等数据的保存和恢复上。
- CPU 缓存命中率
2 性能工具
2.1 根据指标查工具
2.1.1 平均负载
uptime:最简单
$ uptime 02:34:03 up 2 days, 20:14, 1 user, load average: 0.63, 0.83, 0.88
top:提供了更全的指标
# 默认每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 ...
2.1.2 系统整体 CPU 使用率
mpstat
# -P ALL 表示监控所有CPU,后面数字5表示间隔5秒后输出一组数据 $ mpstat -P ALL 5 Linux 4.15.0 (ubuntu) 09/22/18 _x86_64_ (2 CPU) 13:30:06 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle 13:30:11 all 50.05 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 49.95 13:30:11 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 13:30:11 1 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
vmstat
# 每隔5秒输出1组数据 $ 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 0 0 0 7005360 91564 818900 0 0 0 0 25 33 0 0 100 0 0
- top:第 3 行
- sar:可以记录历史数据
- /proc/stat:是性能工具的数据来源
2.1.3 进程 CPU 使用率
pidstat:比 top 提供的指标更详细。
# 间隔5秒后输出一组数据,-u表示CPU指标 $ pidstat -u 5 1 Linux 4.15.0 (ubuntu) 09/22/18 _x86_64_ (2 CPU) 13:42:08 UID PID %usr %system %guest %wait %CPU CPU Command 13:42:13 0 104 0.00 3.39 0.00 0.00 3.39 1 kworker/1:1H 13:42:13 0 109 0.00 0.40 0.00 0.00 0.40 0 kworker/0:1H 13:42:13 0 2997 2.00 35.53 0.00 3.99 37.52 1 stress 13:42:13 0 3057 0.00 0.40 0.00 0.00 0.40 0 pidstat
- ps, top, atop, htop:top 还提供进程的状态。
2.1.4 系统上下文切换
- vmstat:提供上下文切换次数(cs),运行状态和不可中断状态进程的数量(r,b)。
2.1.5 进程上下文切换
pidstat
# 每隔5秒输出1组数据 $ pidstat -w 5 Linux 4.15.0 (ubuntu) 09/23/18 _x86_64_ (2 CPU) 08:18:26 UID PID cswch/s nvcswch/s Command 08:18:31 0 1 0.20 0.00 systemd 08:18:31 0 8 5.40 0.00 rcu_sched ...
# 每隔1秒输出一组数据(需要 Ctrl+C 才结束) # -wt 参数表示输出线程的上下文切换指标 $ pidstat -wt 1 08:14:05 UID TGID TID cswch/s nvcswch/s Command ... 08:14:05 0 10551 - 6.00 0.00 sysbench 08:14:05 0 - 10551 6.00 0.00 |__sysbench 08:14:05 0 - 10552 18911.00 103740.00 |__sysbench 08:14:05 0 - 10553 18915.00 100955.00 |__sysbench 08:14:05 0 - 10554 18827.00 103954.00 |__sysbench ...
2.1.6 软中断
- top:第 3 行的 si 列。
- mpstat:soft 列。
/proc/softirqs
$ watch -d cat /proc/softirqs CPU0 CPU1 HI: 0 0 TIMER: 1083906 2368646 NET_TX: 53 9 NET_RX: 1550643 1916776 BLOCK: 0 0 IRQ_POLL: 0 0 TASKLET: 333637 3930 SCHED: 963675 2293171 HRTIMER: 0 0 RCU: 1542111 1590625
2.1.7 硬中断
- top:第 3 行的 hi 列。
- vmstat:提供总的中断次数(in)。
/proc/interrupts:提供各种中断在每个 CPU 上的累积次数。
# -d 参数表示高亮显示变化的区域 $ watch -d cat /proc/interrupts CPU0 CPU1 ... RES: 2450431 5279697 Rescheduling interrupts ...
2.1.8 网络
dstat
# 间隔1秒输出10组数据 $ dstat 1 10 You did not select any stats, using -cdngy by default. --total-cpu-usage-- -dsk/total- -net/total- ---paging-- ---system-- usr sys idl wai stl| read writ| recv send| in out | int csw 0 0 96 4 0|1219k 408k| 0 0 | 0 0 | 42 885 0 0 2 98 0| 34M 0 | 198B 790B| 0 0 | 42 138 0 0 0 100 0| 34M 0 | 66B 342B| 0 0 | 42 135 0 0 84 16 0|5633k 0 | 66B 342B| 0 0 | 52 177 0 3 39 58 0| 22M 0 | 66B 342B| 0 0 | 43 144 0 0 0 100 0| 34M 0 | 200B 450B| 0 0 | 46 147 0 0 2 98 0| 34M 0 | 66B 342B| 0 0 | 45 134 0 0 0 100 0| 34M 0 | 66B 342B| 0 0 | 39 131 0 0 83 17 0|5633k 0 | 66B 342B| 0 0 | 46 168 0 3 39 59 0| 22M 0 | 66B 342B| 0 0 | 37 134
sar
# -n DEV 表示显示网络收发的报告,间隔1秒输出一组数据 $ sar -n DEV 1 15:03:46 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil 15:03:47 eth0 12607.00 6304.00 664.86 358.11 0.00 0.00 0.00 0.01 15:03:47 docker0 6302.00 12604.00 270.79 664.66 0.00 0.00 0.00 0.00 15:03:47 lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15:03:47 veth9f6bbcd 6302.00 12604.00 356.95 664.66 0.00 0.00 0.00 0.05
tcpdump
# -i eth0 只抓取eth0网卡,-n不解析协议名和主机名 # tcp port 80表示只抓取tcp协议并且端口号为80的网络帧 $ tcpdump -i eth0 -n tcp port 80 15:11:32.678966 IP 192.168.0.2.18238 > 192.168.0.30.80: Flags [S], seq 458303614, win 512, length 0 ...
2.1.9 I/O
- dstat
- sar
2.1.10 CPU 个数
- lscpu
/proc/cpuinfo
$ grep 'model name' /proc/cpuinfo | wc -l 2
2.1.11 事件剖析
perf
$ perf top Samples: 833 of event 'cpu-clock', Event count (approx.): 97742399 Overhead Shared Object Symbol 7.28% perf [.] 0x00000000001f78a4 4.72% [kernel] [k] vsnprintf 4.32% [kernel] [k] module_get_kallsym 3.65% [kernel] [k] _raw_spin_unlock_irqrestore ...
# -g开启调用关系分析,-p指定php-fpm的进程号21515 $ perf top -g -p 21515
# 记录性能事件,等待大约15秒后按 Ctrl+C 退出 $ perf record -g # 查看报告 $ perf report
execsnoop:查看短时进程。
# 按 Ctrl+C 结束 $ execsnoop PCOMM PID PPID RET ARGS sh 30394 30393 0 stress 30396 30394 0 /usr/local/bin/stress -t 1 -d 1 sh 30398 30393 0 stress 30399 30398 0 /usr/local/bin/stress -t 1 -d 1 sh 30402 30400 0 stress 30403 30402 0 /usr/local/bin/stress -t 1 -d 1 sh 30405 30393 0 stress 30407 30405 0 /usr/local/bin/stress -t 1 -d 1 ...
strace:跟踪进程的系统调用。
# strace -p $(pgrep app) strace: Process 4988 attached restart_syscall(<\.\.\. resuming interrupted nanosleep \.\.\.>) = 0 openat(AT_FDCWD, "/dev/sdb1", O_RDONLY|O_DIRECT) = 4 mmap(NULL, 33558528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f448d240000 read(4, "8vq\213\314\264u\373\4\336K\224\25@\371\1\252\2\262\252q\221\n0\30\225bD\252\266@J"\.\.\., 33554432) = 33554432 write(1, "Time used: 0.948897 s to read 33"\.\.\., 45) = 45 close(4) = 0
2.1.12 进程的父子关系
pstree
$ pstree | grep stress |-docker-containe-+-php-fpm-+-php-fpm---sh---stress | |-3*[php-fpm---sh---stress---stress]
# -a 表示输出命令行选项 # p表PID # s表示指定进程的父进程 $ pstree -aps 3084 systemd,1 └─dockerd,15006 -H fd:// └─docker-containe,15024 --config /var/run/docker/containerd/containerd.toml └─docker-containe,3991 -namespace moby -workdir... └─app,4009 └─(app,3084)
2.2 根据工具查指标
- uptime:平均负载。
- top:平均负载,运行队列长度,整体 CPU 使用率,每个进程的 CPU 使用率和状态。
- vmstat: 系统整体 CPU 使用率,上下文切换次数,中断次数,处于运行和不可中断状态的进程数量。
- mpstat:每个 CPU 的使用率和软中断次数。
- pidstat:进程的 CPU 使用率,中断上下文切换次数。
- ps:每个进程的状态和 CPU 使用率。
- pstree:进程间的父子关系。
- dstat:系统整体的 CPU 使用率,网络。
- sar:网络。
- strace:进程的系统调用。
- perf:CPU 性能事件剖析,如调用链分析、CPU 缓存、CPU 调度等。
- execsnoop:监控短时进程。
3 如何快速 CPU 的性能瓶颈
例如:
- 当通过 top 分析到 CPU 使用率高,可通过 pidstat 查看哪个进程 CPU 使用率高,进而通过 strace 分析系统调用情况以及用 perf 分析调用链中各级函数调用情况。
- 当通过 top 分析到平均负载高,可通过 vmstat 分析运行状态和不可中断状态的进程哪种导致的,如果是运行状态进程导致的,需要通过 top 和 pidstat 分析进程;否则,需要通过 dstat 或 sar 进一步分析 I/O。
- 当发现软中断导致 CPU 使用率高,可通过查看 /proc/softirqs 查看哪种软中断导致的,如果是网络中断导致的,可通过 sar 和 tcpdump 进一步分析。
参考
倪朋飞. Linux 性能优化实战.
没有评论