10-案例篇:系统的软中断CPU使用率升高,我该怎么办?





中断

中断是一种异步的事件处理机制,用来提高系统的并发处理能力
中断事件发生,会触发执行中断处理程序,而中断处理程序被分为上半部和下半部这两个部分

1.上半部对应硬中断,用来快速处理中断
2.下半部对应软中断,用来异步处理上半部未完成的工作

Linux中的软中断包括网络收发、定时、调度、RCU 锁等各种类型
可以查看proc文件系统中的/proc/softirqs观察软中断的运行情况

在Linux中,每个CPU都对应一个软中断内核线程,名字是ksoftirqd/CPU编号
当软中断事件的频率过高时,内核线程也会因为CPU使用率过高而导致软中断处理不及时,
进而引发网络收发延迟、调度缓慢等性能问题

软中断CPU使用率过高也是一种最常见的性能问题




案例

实验环境
# 服务端(192.168.1.6)
配置:2CPU,4G内存,centos7.6_64     
预先安装docker、tcpdump、sar等工具(yum install tcpdump、sar)


# 客户端(192.168.1.5)
配置:1CPU,2G内存,centos7.6_64 
# 预先安装hping3工具
[root@local_deploy_192-168-1-5 ~]# yum install hping3 -y


工具介绍
sar     是一个系统活动报告工具,既可以实时查看系统的当前活动,又可以配置保存和报告历史统计数据

hping3  是一个可以构造TCP/IP协议数据包的工具,可以对系统进行安全审计、防火墙测试等

tcpdump 是一个常用的网络抓包工具,常用来分析各种网络问题


1.本次实验架构图

image-20211117155641002

其中一台虚拟机运行Nginx ,用来模拟待分析的Web服务器
另一台当作Web服务器的客户端,用来给Nginx增加压力请求


2.在服务端,启动一个nginx应用

# 运行Nginx服务并对外开放80端口
[root@local_sa_192-168-1-6 ~]# docker run -itd --name=nginx -p 80:80 nginx


# 使用 curl 访问Nginx监听的端口,确认Nginx正常启动
[root@local_sa_192-168-1-6 ~]# curl http://192.168.1.6
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
......


3.在客户端,使用hping3,模拟对nginx的请求

# -S 参数表示设置TCP协议的SYN(同步序列号)
# -p 表示目的端口为80
# -i u100表示每隔100微秒发送一个网络帧
# 注:如果你在实践过程中现象不明显,可以尝试把100调小,比如调成10甚至1
[root@local_deploy_192-168-1-5 ~]# hping3 -S -p 80 -i u10 192.168.1.6

# hping3这是一个SYN FLOOD攻击
# 此时查看服务器开始卡顿


4.在服务端,发现服务端开始卡顿,使用top命令查看

# top运行后按数字1切换到显示所有CPU
[root@local_sa_192-168-1-6 ~]# top
top - 10:50:58 up 1 days, 22:10, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 122 total, 1 running, 71 sleeping, 0 stopped, 0 zombie
%Cpu0 : 0.0 us, 0.0 sy, 0.0 ni, 96.7 id, 0.0 wa, 0.0 hi, 3.3 si, 0.0 st
%Cpu1 : 0.0 us, 0.0 sy, 0.0 ni, 95.6 id, 0.0 wa, 0.0 hi, 4.4 si, 0.0 st
...
 PID  USER PR NI  VIRT    RES   SHR   S %CPU %MEM TIME+   COMMAND
 7    root 20 0   0       0     0     S 0.3  0.0  0:01.64 ksoftirqd/0
 16   root 20 0   0       0     0     S 0.3  0.0  0:01.97 ksoftirqd/1
 2663 root 20 0   923480  28292 13996 S 0.3  0.3  4:58.66 docker-containe
 3699 root 20 0   0       0     0     I 0.3  0.0  0:00.13 kworker/u4:0
 3708 root 20 0   44572   4176  3512  R 0.3  0.1  0:00.07 top
 1    root 20 0   225384  9136  6724  S 0.0  0.1  0:23.25 systemd
 2    root 20 0   0       0     0     S 0.0  0.0  0:00.03 kthreadd
...

# 输出结果分析
平均负载全是0,就绪队列里面只有一个进程(1 running)
每个CPU的使用率都挺低,最高的CPU1的使用率也只有4.4%,并不算高
再看进程列表,CPU使用率最高的进程也只有0.3%,还是不高呀

仔细看top的输出,两个CPU的使用率虽然分别只有3.3%和4.4%,但都用在了软中断上
而从进程列表上也可以看到,CPU使用率最高的也是软中断进程ksoftirqd
看起来,软中断有点可疑了


5.在服务端,查看中断次数的变化速率

/proc/softirqs文件它是系统运行以来的累积中断次数
直接查看文件内容,得到的只是累积中断次数,对这里的问题并没有直接参考意义
【中断次数的变化速率】才是需要关注的

# watch 命令可以定期运行一个命令来查看输出
# -d 以高亮出变化的部分
[root@local_sa_192-168-1-6 ~]# 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工具


6.在服务端,使用sar工具分析

# sar 可以用来查看系统的网络收发情况
# 不仅可以观察网络收发的吞吐量(BPS,每秒收发的字节数)
# 还可以观察网络收发的PPS,即每秒收发的网络帧数

# -n DEV表示显示网络收发的报告,间隔1秒输出一组数据
[root@local_sa_192-168-1-6 ~]# sar -n DEV 1
15:03:46   IFACE        rxpck/s   txpck/s   rxkB/s   txkB/s   rxcmp/s   txcmp/s  rxmcs
15:03:47   eth0         12607.00  6304.00   664.86   358.11   0.00      0.00     0
15:03:47   docker0      6302.00   12604.00  270.79   664.66   0.00      0.00     0
15:03:47   lo           0.00      0.00      0.00     0.00     0.00      0.00     0
15:03:47   veth9f6bbcd  6302.00   12604.00  356.95   664.66   0.00      0.00     0

# 输出结果介绍
第一列:表示报告的时间
第二列:IFACE 表示网卡
第三、四列:rxpck/s和txpck/s分别表示每秒接收、发送的网络帧数,也就是PPS
第五、六列:rxkB/s和txkB/s 分别表示每秒接收、发送的千字节数,也就是BPS

# 分析
对网卡eth0来说,每秒接收的网络帧数比较大,达到了12607,而发送的网络帧数则比较小,只有6304
每秒接收的千字节数只有664KB,而发送的千字节数更小,只有358KB

docker0和veth9f6bbcd的数据跟eth0基本一致,只是发送和接收相反,发送的数据较大而接收的数据较小
这是Linux内部网桥转发导致的,是系统把eth0收到的包转发给Nginx服务


从这些数据中分析
既然怀疑是网络接收中断的问题,重点来看eth0
接收的PPS比较大,达到12607,而接收的BPS却很小,只有664KB
直观来看网络帧应该都是比较小的
稍微计算一下,664*1024/12607 = 54字节,
说明平均每个网络帧只有54字节,这显然是很小的网络帧,也就是通常所说的小包问题

查看网络帧从哪里发送过来的


7.在服务端,tcpdump工具抓包

# tcpdump抓取eth0上的包就可以了
# 已经知道,Nginx监听在80端口,它所提供的HTTP服务是基于TCP协议的,
# 所以可以指定TCP协议和80端口精确抓包

# -i eth0只抓取eth0网卡
# -n 不解析协议名和主机名
# tcp port 80 表示只抓取tcp协议并且端口号为80的网络帧
[root@local_sa_192-168-1-6 ~]# tcpdump -i eth0 -n tcp port 80
:34:27.439264 IP 192.168.1.5.51070 > 192.168.1.6.http: Flags [S], seq 2133566800, win 512, length 0

# 输出结果分析
192.168.1.5.51070 > 192.168.1.6.http 表示网络帧从192.168.1.5的51070端口发送到
192.168.1.6的80(http)端口
也就是从运行hping3机器的51070端口发送网络帧,目的为Nginx所在机器的80端口
Flags[S]则表示这是一个SYN包

再加上前面用sar发现的,PPS超过12000的现象,
现在可以确认,这就是从192.168.1.5 这个地址发送过来的SYN FLOOD攻击


8.最终分析

到这里,已经做了全套的性能诊断和分析
从系统的软中断使用率高这个现象出发
通过观察/proc/softirqs文件的变化情况
判断出软中断类型是网络接收中断
再通过sar和tcpdump,确认这是一个SYN FLOOD问题

SYN FLOOD问题最简单的解决方法,就是从交换机或者硬件防火墙中封掉来源IP
这样SYN FLOOD网络帧就不会发送到服务器中

关于SYN FLOOD的原理和更多解决思路,可以关注后面的博客




小结

软中断CPU使用率(softirq)升高是一种很常见的性能问题
虽然软中断的类型很多
但实际生产中,遇到的性能瓶颈大多是网络收发类型的软中断,特别是网络接收的软中断

在碰到这类问题时,可以借用sar、tcpdump等工具,做进一步分析


posted @ 2021-11-17 16:59  李成果  阅读(1121)  评论(0编辑  收藏  举报