02 | 基础篇:到底应该怎么理解“平均负载”?
当平均负载高于cpu数量70%的时候,就应该分析排查负载高的问题。
watch -d uptime 查看cpu负载变化的命令
grep 'model name' /proc/cpuinfo | wc -l 查看系统cpu个数
stress是一个linux系统压力测试工具
stress --cpu 1 --timeout 600 模拟一个cpu使用率100%的场景
stress -i 1 --timeout 600 模拟I/O压力,即不停地执行sync
stress -c 8 --timeout 600 模拟8个进程,当运行进程超出cpu运行能力时,就会出现等待cpu的进程
mpstat -P ALL 5 查看cpu使用率的变化情况,每隔5秒输出一组数据
pidstat -u 5 1 间隔5秒输出一组数据,查看哪个进程导致cpu使用率100%
CPU使用率是单位时间内CPU繁忙的情况的统计,跟平均负载并不一定完全对应。
- CPU密集型进程,使用大量CPU会导致平均负载升高,此时这两者是一致的。
- I/O密集型进程,等待I/O也会导致平均负载升高,但CPU使用率不一定很高。
- 大量等待CPU的进程调度也会导致平均负载升高,此时CPU使用率也会比较高。
03 | 基础篇:经常说的 CPU 上下文切换是什么意思?(上)
根据任务的不同,CPU的上下文切换就可以分为几个不同的场景,也就是进程上下文切换、线程上下文切换以及中断上下文切换。
一次系统调用的过程,其实是发生两次CPU上下文切换。系统调用过程通常称为特权模式切换,而不是上下文切换。但实际上,系统调用过程中,CPU的上下文切换还是无法避免的。
过多的上下文切换,会把CPU时间消耗在寄存器、内核栈以及虚拟内存等数据的保存与恢复上,从而缩短进程真正运行的时间,导致系统的整体性能大幅下降。
04 | 基础篇:经常说的 CPU 上下文切换是什么意思?(下)
# 每隔 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
cs(context switch)是每秒上下文切换的次数
in(interrupt)是每秒中断的次数
r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待cpu的进程数
b(Blocked)则是处于不可中断睡眠状态的进程数
# 每隔 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
cswch(voluntary context switches)每秒自愿上下文切换的次数,nvcswch是非自愿
自愿上下文切换:指进程无法获取所需资源,导致的上下文切换。如I/O、内存等系统资源不足。
非自愿上下文切换:指进程时间片已到等原因,被系统强制调度。如大量进程都在抢CPU时。
用sysbench --threads=10 --max-time=300 threads run模拟上下文切换
分析pidstat得出sysbench占用cpu,而pidstat、kworker、sshd的上下文切换多
# 每隔 1 秒输出 1 组数据(需要 Ctrl+C 才结束)
# -w 参数表示输出进程切换指标,而 -u 参数则表示输出 CPU 使用指标
$ pidstat -w -u 1
08:06:33 UID PID %usr %system %guest %wait %CPU CPU Command
08:06:34 0 10488 30.00 100.00 0.00 0.00 100.00 0 sysbench
08:06:34 0 26326 0.00 1.00 0.00 0.00 1.00 0 kworker/u4:2
08:06:33 UID PID cswch/s nvcswch/s Command
08:06:34 0 8 11.00 0.00 rcu_sched
08:06:34 0 16 1.00 0.00 ksoftirqd/1
08:06:34 0 471 1.00 0.00 hv_balloon
08:06:34 0 1230 1.00 0.00 iscsid
08:06:34 0 4089 1.00 0.00 kworker/1:5
08:06:34 0 4333 1.00 0.00 kworker/0:3
08:06:34 0 10499 1.00 224.00 pidstat
08:06:34 0 26326 236.00 0.00 kworker/u4:2
08:06:34 1000 26784 223.00 0.00 sshd
查看进程对应的线程的上下文切换
# 每隔 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
查看到中断次数增多的原因
# -d 参数表示高亮显示变化的区域
$ watch -d cat /proc/interrupts
CPU0 CPU1
...
RES: 2450431 5279697 Rescheduling interrupts
...
05 | 基础篇:某个应用的CPU使用率居然达到100%,我该怎么办?
压测代码
ab -c 10 -n 10000 http://10.240.0.5:10000/
top查看cpu占用率高的程序
perf top进上步查看调用关系
# -g 开启调用关系分析,-p 指定 php-fpm 的进程号 21515
$ perf top -g -p 21515
定位到函数
06 | 案例篇:系统的 CPU 使用率很高,但为啥却找不到高 CPU 的应用?
# 记录性能事件,等待大约 15 秒后按 Ctrl+C 退出
$ perf record -g
# 查看报告
$ perf report
常规问题无法解释cpu使用率情况时,首先要想到可能短时间应用导致的问题:
1、应用里直接调用了其他二进制程序,这些程序通常运行时间短,通过top工具不易发现
2、应用本身在不停地崩溃重启,而启动过程的资源初始化,很可能会占用相当多的cpu。
07 | 案例篇:系统中出现大量不可中断进程和僵尸进程怎么办?(上)
用我们熟悉的ps和top命令可以查看进程状态,这些状态包括运行(R)、空闲(I)、不可中断睡眠(D)、可中断睡眠(S)、僵尸(Z)以及暂停(T)等。
不可中断睡眠:表示进程正在跟硬件交互,为了保护进程数据和硬件的一致性,系统不允许其它进程或中断打断这个进程。进程长时间处于不可中断状态,通常表示系统有I/O性能问题。
僵尸进程表示进程已经退出,但它的父进程还没有回收子进程占用的资源。短暂的僵尸进程状态我们通常不会管理,但进程长时间处于僵尸状态,就应该注意了,可能应用程序没有正常处理子进程的退出。
08 | 案例篇:系统中出现大量不可中断进程和僵尸进程怎么办?(下)
dstat命令观察cpu和i/o的使用情况
# 间隔 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
要解决僵尸进程需要找出父进程,也就是它们的根
# -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)
09 | 基础篇:怎么理解Linux软中断?
Linux中的中断处理程序分为上半部分和下半部分
上半部分对应硬件中断,用来快速处理中断
下半部对应软中断,用来异步处理上半部分未完成的工作
10 | 案例篇:系统的软中断CPU使用率升高,我该怎么办?
机器A运行以下命令:
docker run -itd --name=nginx -p 80:80 nginx
机器B运行hping3,发起syn flood攻击,此操作会导致目标主机网络高延迟,ssh连上去敲命令卡顿,甚于无法操作,解决方案是从交换机或硬件防火墙封掉攻击ip,这样SYN FLOOD网络帧就不会发送到服务器:
# -S 参数表示设置 TCP 协议的 SYN(同步序列号),-p 表示目的端口为 80
# -i u100 表示每隔 100 微秒发送一个网络帧
# 注:如果你在实践过程中现象不明显,可以尝试把 100 调小,比如调成 10 甚至 1
$ hping3 -S -p 80 -i u100 192.168.0.30
机器A进行问题排查
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
通过 /proc/softirqs 文件内容的变化情况,你可以发现, TIMER(定时中断)、NET_RX(网络接收)、SCHED(内核调度)、RCU(RCU 锁)等这几个软中断都在不停变化。
其中,NET_RX,也就是网络数据包接收软中断的变化速率最快。而其他几种类型的软中断,是保证 Linux 调度、时钟和临界区保护这些正常工作所必需的,所以它们有一定的变化倒是正常的。
sar 可以用来查看系统的网络收发情况,还有一个好处是,不仅可以观察网络收发的吞吐量(BPS,每秒收发的字节数),还可以观察网络收发的 PPS,即每秒收发的网络帧数。
# -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
对网卡 eth0 来说,每秒接收的网络帧数比较大,怀疑是网络接收中断的问题。
那么,有没有办法知道这是一个什么样的网络帧,以及从哪里发过来的呢?
使用 tcpdump 抓取 eth0 上的包就可以了。
# -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
...
Flags [S] 则表示这是一个 SYN 包。
再加上前面用 sar 发现的, PPS 超过 12000 的现象,现在我们可以确认,这就是从 192.168.0.2 这个地址发送过来的 SYN FLOOD 攻击。
11 | 套路篇:如何迅速分析出系统CPU的瓶颈在哪里?
12 | 套路篇:CPU 性能优化的几个思路
CPU优化分为应用程序优化和系统优化。
应用程序优化:编译器优化、算法优化、异步处理、多线程代替多进程、善用缓存
系统优化:CPU绑定、CPU独占、优先级调整、为进程设置资源限制、NUMA(Non-Uniform Memory Access) 优化、中断负载均衡
Buffer既可以用作“将要写入磁盘数据的缓存”,也可以用作“从磁盘读取数据的缓存”
Cache既可以用作“从文件读取数据的页缓存”,也可以用作“写文件的页缓存”
OSI网络模型
应用层--->表示层-->会话层-->传输层-->网络层-->数据链路层-->物理层