系统的软中断CPU使用率升高,我该怎么办?

  • 前言
  • 案例
  • 操作和分析
  • 总结


前言

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

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

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

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

软中断 CPU 使用率过高也是一种最常见的性能问题。下面我们就用最常见的反向代理服务器 Nginx 的案例,来学会分析这种情况。

案例

预先安装 docker、sysstat、sar 、hping3、tcpdump 等工具。

  • sar 是一个系统活动报告工具,既可以实时查看系统的当前活动,又可以配置保存和报 告历史统计数据。
  • hping3 是一个可以构造 TCP/IP 协议数据包的工具,可以对系统进行安全审计、防火墙 测试等。
  • tcpdump 是一个常用的网络抓包工具,常用来分析各种网络问题。

本次案例用到两台机器,用一张图来表示它们的关系。

centos 软中断优化 软中断占用cpu过高_Nginx


可以看到,其中一台虚拟机运行 Nginx ,用来模拟待分析的 Web 服务器;而另一台当 作 Web 服务器的客户端,用来给 Nginx 增加压力请求。使用两台虚拟机的目的,是为了 相互隔离,避免“交叉感染”。

接下来,我们打开两个终端,分别 SSH 登录到两台机器上,并安装上面提到的这些工具。

操作和分析

在客户端机,使用 curl 访问 Nginx 监听的端口,确认 Nginx 正常启动。

# curl http://192.91.16.101
<!DOCTYPE html>
<html>
<head>
<title>Nginx</title>
<meta charset="utf-8">
<meta name="author" content="Licess">
</head>
<body>
<div id="main">
<div align="center"><b欢迎访问nginx</b></div>

</div>
</body>
</html>

接着,还是在第客户端机,我们运行 hping3 命令,来模拟 Nginx 的客户端请求:

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

再回到第一个终端,你应该发现了异常。是不是感觉系统响应明显变慢了,即便只是在终端中敲几个回车,都得很久才能得到响应?这个时候应该怎么办呢?

那么,该从什么地方入手呢?刚才我们发现,简单的 SHELL 命令都明显变慢了,先看看系 统的整体资源使用情况应该是个不错的注意,比如执行下 top 看看是不是出现了 CPU 的 瓶颈。我们在第一个终端运行 top 命令,看一下系统整体的资源使用情况。

top
Tasks: 146 total,   2 running, 144 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.0 us,  0.3 sy,  0.0 ni, 50.0 id,  0.0 wa,  3.7 hi, 46.0 si,  0.0 st
%Cpu1  :  0.0 us,  0.0 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.3 hi,  0.0 si,  0.0 st
MiB Mem :   3637.6 total,    639.2 free,    811.5 used,   2187.0 buff/cache
MiB Swap:   4096.0 total,   4091.2 free,      4.8 used.   2554.3 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                                                                
    9 root      20   0       0      0      0 R   0.3   0.0   0:02.58 ksoftirqd/0                                                                                            
   10 root      20   0       0      0      0 I   0.3   0.0   4:18.81 rcu_sched                                                                                              
  805 root      20   0  233936   5936   5108 S   0.3   0.2   2:29.64 rngd                                                                                                   
32087 root      10 -10  178848  33376  15456 S   0.3   0.9 109:22.08 AliYunDun                                                                                              
    1 root      20   0  176960  10692   8040 S   0.0   0.3   1:17.62 systemd                                                                                                
....

这里我们有没有发现异常的现象?我们从第一行开始,逐个看一下:

平均负载全是 0,就绪队列里面只有一个进程(1 running)。

每个 CPU 的使用率都挺低,最高的 CPU1 的使用率也只有 4.4%,并不算高。 再看进程列表,CPU 使用率最高的进程也只有 0.3%,还是不高呀。

那么我们使用sar 命令来看一下网络收发的报告:

# -n DEV 表示显示网络收发的报告,间隔 1 秒输出一组数据
sar-n DEV 1
Linux 4.18.0-147.5.1.el8_1.x86_64 (service) 	2021年07月02日 	_x86_64_	(2 CPU)

15时09分17秒     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
15时09分18秒        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15时09分18秒      eth0  15542.00   7773.00    910.68    444.02      0.00      0.00      0.00      0.00

15时09分18秒     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
15时09分19秒        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15时09分19秒      eth0  15541.00   7771.00    910.61    440.28      0.00      0.00      0.00      0.00

15时09分19秒     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
15时09分20秒        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15时09分20秒      eth0  15202.00   7602.00    890.75    431.15      0.00      0.00      0.00      0.00

15时09分20秒     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
15时09分21秒        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15时09分21秒      eth0  15565.00   7784.00    912.00    441.44      0.00      0.00      0.00      0.00

对于 sar 的输出界面,我先来简单介绍一下,从左往右依次是:

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

我们具体来看输出的内容,可以发现:
对网卡 eth0 来说,每秒接收的网络帧数比较大,达到了 15565.00,而发送的网络帧数则 比较小,只有 7784.00;每秒接收的千字节数只有 912 KB,而发送的千字节数更小,只有 441.44 KB。

既然怀疑是网络接收中断的问题,我们还是重点来看 eth0 :接收的 PPS 比较大,达到 15565.00,而接收的 BPS 却很小,只有 912 KB。直观来看网络帧应该都是比较小的,我们 稍微计算一下,912*1024/15565 = 59 字节,说明平均每个网络帧只有 59 字节,这显然是很小的网络帧,也就是我们通常所说的小包问题。

那么,有没有办法知道这是一个什么样的网络帧,以及从哪里发过来的呢?

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

接下来,我们在第一个终端中运行 tcpdump 命令,通过 -i eth0 选项指定网卡 eth0,并 通过 tcp port 80 选项指定 TCP 协议的 80 端口:

[root@ default]# tcpdump -i eth0 -n tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
15:38:44.003066 IP 47.243.28.161.24559 > 172.31.36.79.http: Flags [R], seq 1163136593, win 0, length 0
15:38:44.003181 IP 47.243.28.161.24569 > 172.31.36.79.http: Flags [S], seq 621341255, win 512, length 0
15:38:44.003187 IP 172.31.36.79.http > 47.243.28.161.24569: Flags [S.], seq 3012841219, ack 621341256, win 29200, options [mss 1460], length 0
15:38:44.003192 IP 47.243.28.161.24560 > 172.31.36.79.http: Flags [R], seq 406564800, win 0, length 0
....

从 tcpdump 的输出中,可以发现:
47.243.28.161.24559 > 172.31.36.79,表示网络帧从 47.243.28.161 的 24559 端口发送到 172.31.36.79 的 80 端口,也就是从运行 hping3 机器的 24559 端口发送网络 帧,目的为 Nginx 所在机器的 80 端口。

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

总结

软中断 CPU 使用率(softirq)升高是一种很常见的性能问题。虽然软中断的类型很多, 但实际生产中,我们遇到的性能瓶颈大多是网络收发类型的软中断,特别是网络接收的软中断。在碰到这类问题时,你可以借用 sar、tcpdump 等工具,做进一步分析。