本文介绍Linux服务器CPU性能评估和优化的基本方法。
平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和 CPU 使用率并没有直接关系。所谓可运行状态的进程,是指正在使用 CPU 或者正在等待 CPU 的进程,也就是我们常用 ps 命令看到的,处于 R 状态(Running 或 Runnable)的进程。不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的 I/O 响应,也就是我们在 ps 命令中看到的 **D 状态(Uninterruptible Sleep,也称为 Disk Sleep)**的进程。
平均负载最理想的情况是等于 CPU 个数。所以在评判平均负载时,首先要知道系统有几个 CPU,这可以通过 top
命令或者从文件 /proc/cpuinfo
中读取。
# wc表示word count, -l表示显示文本的行数, 每行表示一个CPU,因此行数表示有几个CPU
ty@ubuntu:~$ grep 'model name' /proc/cpuinfo | wc -l
1
平均负载的查询可以通过uptime
进行,实时状态变化则使用watch -d uptime
# watch 表示实时变化,-d表示高亮变化的位,uptime
$ watch -d uptime
02:34:03 up 2 days, 20:14, 1 user, load average: 0.63, 0.83, 0.88
平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。而 CPU 使用率是单位时间内 CPU 繁忙情况的统计,跟平均负载并不一定完全对应。
为了监测CPU的使用率,通常可以使用mpstat
和pidstat
。
mpstat
是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标。pidstat
是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标,可以查看到底是哪个进程导致了 CPU 使用率上升。# -P ALL 表示监控所有CPU,数字5表示间隔5秒后输出一组数据,后面再加个单独的1的话表示仅输出1组即退出
ty@ubuntu:~$ mpstat -P ALL 5
Linux 4.15.0-112-generic (ubuntu) 08/28/2020 _x86_64_ (1 CPU)
06:28:36 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
06:28:41 AM all 0.00 0.00 0.40 0.00 0.00 0.00 0.00 0.00 0.00 99.60
06:28:41 AM 0 0.00 0.00 0.40 0.00 0.00 0.00 0.00 0.00 0.00 99.60
# 间隔5秒后输出一组数据
ty@ubuntu:~$ pidstat -u 5 1
Linux 4.15.0-112-generic (ubuntu) 08/28/2020 _x86_64_ (1 CPU)
06:30:04 AM UID PID %usr %system %guest %CPU CPU Command
06:30:09 AM 0 381 0.00 0.20 0.00 0.20 0 vmtoolsd
Average: UID PID %usr %system %guest %CPU CPU Command
Average: 0 381 0.00 0.20 0.00 0.20 - vmtoolsd
CPU 使用率,就是除了空闲时间外的其他时间占总 CPU 时间的百分比。我们就可以从 /proc/stat 中的数据,很容易地计算出 CPU 使用率。当然,也可以用每一个场景的 CPU 时间,除以总的 CPU 时间,计算出每个场景的 CPU 使用率。事实上,为了计算 CPU 使用率,性能工具一般都会取间隔一段时间(比如 3 秒)的两次值,作差后,再计算出这段时间内的平均 CPU 使用率,即
top 和 ps 是最常用的性能分析工具:
对比一下 top 和 ps 这两个工具报告的 CPU 使用率,默认的结果很可能不一样,因为 top 默认使用 3 秒时间间隔,而 ps 使用的却是进程的整个生命周期。以下是CPU使用率的主要指标
对于CPU使用率高的问题,主要有两种方式可以查找对应的热点函数或进程
perf top
,它能够实时显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数。perf record
和perf report
。perf top
虽然实时展示了系统的性能信息,但它的缺点是并不保存数据,也就无法用于离线或者后续的分析。而 perf record
则提供了保存数据的功能,保存后的数据,需要用 perf report
解析展示。 碰到常规问题无法解释的 CPU 使用率情况时,首先要想到有可能是短时应用导致的问题,比如有可能是下面这两种情况,可以结合pstree
以及perf record
分析,也可以使用execsnoop
。
vmstat 是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU 上下文切换和中断的次数。
ty@ubuntu:~$ vmstat 5 1
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 268 266720 99700 917660 0 0 317 231 77 273 1 1 96 2 0
除此之外,还可以通过pidstat -w
来细分主动调度和被动调度,即自愿上下文切换cswch(voluntary context switches)和非自愿上下文切换nvcswch(non voluntary context switches)。
# w表示输出进程切换指标,t表示输出线程切换指标,u表示输出CPU使用指标
ty@ubuntu:~$ pidstat -w -u -t 1
Linux 4.15.0-112-generic (ubuntu) 08/29/2020 _x86_64_ (1 CPU)
08:51:22 AM UID TGID TID %usr %system %guest %CPU CPU Command
08:51:23 AM 0 1269 - 2.02 0.00 0.00 2.02 0 Xorg
08:51:23 AM 0 - 1269 1.01 0.00 0.00 1.01 0 |__Xorg
08:51:23 AM 0 - 1616 0.00 1.01 0.00 1.01 0 |__InputThread
08:51:23 AM 1000 - 2638 1.01 0.00 0.00 1.01 0 |__ibus-daemon
08:51:22 AM UID TGID TID cswch/s nvcswch/s Command
08:51:23 AM 0 7 - 9.09 0.00 ksoftirqd/0
08:51:23 AM 0 - 7 9.09 0.00 |__ksoftirqd/0
08:51:23 AM 0 8 - 34.34 0.00 rcu_sched
......
一般来说,如果CPU上下文切换次数异常升高,主要可以从以下角度考虑
对于此类问题我们通常可以使用top
或者ps
进行观察。首先看看进程状态的分类:
除此之外,还可以使用dstat
命令观察CPU和I/O的使用情况。
# 每1秒输出一次,共输出5次
ty@ubuntu:~$ dstat 1 5
You did not select any stats, using -cdngy by default.
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read writ| recv send| in out | int csw
8 15 54 24 0 0|6105k 89k| 0 0 | 0 0 | 352 1896
0 0 100 0 0 0| 56k 0 | 0 0 | 0 0 | 74 198
0 0 99 0 0 1| 0 0 | 0 0 | 0 0 | 215 483
0 0 100 0 0 0| 0 0 | 120B 0 | 0 0 | 113 298
0 0 100 0 0 0| 0 0 | 60B 0 | 0 0 | 260 634
软中断 CPU 使用率(softirq)升高是一种很常见的性能问题。虽然软中断的类型很多,但实际生产中,我们遇到的性能瓶颈大多是网络收发类型的软中断,特别是网络接收的软中断,除此之外还有可能来自于定时、调度、RCU锁等。通过top
命令可以观察软中断是否较多。
对于软中断较多的情况,可以监控/proc/softirqs
来观察到底是哪种软中断过多,主要有TIMER(定时中断)、NET_RX(网络接收)、SCHED(内核调度)、RCU(RCU 锁)等这几个软中断。
$ 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
针对网络收发导致的软中断,我们可以通过sar
查看并比较出是否出现了小包问题等,最后通过tcmdump
进行更深入的抓包分析。
# -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
stress 是一个 Linux 系统压力测试工具,可以用作异常进程模拟平均负载升高的场景。
stress基于多进程的,会fork多个进程,导致进程上下文切换,导致us开销很高;
# --cpu表示模拟CPU,1表示100%,-i表示I/O压力测试,-c表示进程
$ stress --cpu 1 --timeout 600
$ stress -i 1 --timeout 600
$ stress -c 8 --timeout 600
sysbench 是一个多线程的基准测试工具,一般用来评估不同系统参数下的数据库负载情况,也可以用于模拟上下文切换过多的问题。
sysbench基于多线程的,会创建多个线程,单一进程基于内核线程切换,导致sy的内核开销很高;
root@ubuntu:/home/ty# sysbench --num-threads=10 --max-time=300 --max-requests=10000000 --test=threads run
sysbench 0.4.12: multi-threaded system evaluation benchmark
Running the test with following options:
Number of threads: 10
Doing thread subsystem performance test
Thread yields per test: 1000 Locks used: 8
Threads started!
ab是apache自带的压力测试工具。ab非常实用,它不仅可以对apache服务器进行网站访问压力测试,也可以对或其它类型的服务器进行压力测试。比如nginx、tomcat、IIS等。
# c表示并发数, n表示测试次数, 还可以用t来指定测试时间
ty@ubuntu:~$ ab -c 10 -n 100 http://192.168.11.129:10000/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.11.129 (be patient).....done
Server Software: nginx/1.15.4
Server Hostname: 192.168.11.129
Server Port: 10000
Document Path: /
Document Length: 9 bytes
Concurrency Level: 10
Time taken for tests: 1.038 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 17200 bytes
HTML transferred: 900 bytes
Requests per second: 96.31 [#/sec] (mean)
Time per request: 103.826 [ms] (mean)
Time per request: 10.383 [ms] (mean, across all concurrent requests)
Transfer rate: 16.18 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.2 0 1
Processing: 70 101 25.0 94 248
Waiting: 69 101 25.0 93 248
Total: 71 101 25.1 94 248
Percentage of the requests served within a certain time (ms)
50% 94
66% 95
75% 97
80% 98
90% 130
95% 151
98% 200
99% 248
100% 248 (longest request)
hping3
可以用来发送HTTP请求,模拟Nginx的客户端操作
# -S参数表示设置TCP协议的SYN(同步序列号),-p表示目的端口为80
# -i u100表示每隔100微秒发送一个网络帧,通过该方法可以模拟SYN攻击
$ hping3 -S -p 80 -i u100 192.168.0.30
首先,从应用程序的角度来说,降低 CPU 使用率的最好方法当然是排除所有不必要的工作,只保留最核心的逻辑。比如减少循环的层次、减少递归、减少动态内存分配等等。除此之外,应用程序的性能优化也包括很多种方法。
从系统的角度来说,优化 CPU 的运行,一方面要充分利用 CPU 缓存的本地性,加速缓存访问;另一方面,就是要控制进程的 CPU 使用情况,减少进程间的相互影响。具体来说,系统层面的 CPU 优化方法也有不少。
优化永远是谋定而后动的事,在做好充分的测评后再有针对性的进行,才能够以最小的代价获得最大的收益。
[1] Linux-insides
[2] 深入理解Linux内核
[3] Linux内核设计的艺术
[4] 深入理解计算机系统
[5] 深入理解Linux网络技术内幕
[6] shell脚本编程大全
[7] 极客时间 Linux性能优化实战
[8] 极客时间 系统性能调优必知必会