1. 怎么去理解
前面博客简单说过中断的含义,中断是系统用来响应硬件设备请求的一种机制,会打断进程的正常调度和运行,然后调用内核中的中断处理程序来响应硬件设备的请求。
为什么要有中断?其实中断是一种异步的事件处理机制,可以提高系统的并发处理能力。由于中断处理程序会打断进程的运行,特别是还会临时关闭中断,会导致上一次中断处理程序完成以前,其他中断都不能响应,那么这种情况下中断也可能会丢失,所以为了减少对进程的调度和运行的影响,中断处理程序要尽可能快的执行。
在Linux中,为了解决中断处理程序运行时间过长或者中断丢失的问题,将中断分为两个部分,上半部和下半部:
- 上半部用来快速处理中断,他在中断禁止的模式下运行,主要处理跟硬件紧密相关的或者时间敏感的工作。
- 下半部用来延迟处理上半部未完成的工作,通常以内核线程的方式运行,并且每个CPU对应一个软中断内核线程,名字为“ksoftirqd/CPU编号”。另外,软中断不仅仅是刚刚说的硬件设备中断处理程序的下半部,一些内核的自定义事件也是,比如网络收发、定时、内核调度和RCU(Read-Copy Update的缩写,Linux内核最常用的锁之一)等。
举个例子来帮助理解,网卡收包:
网卡收包,会通过硬中断的方式,通知内核有数据到达,内核就应该调用中断处理程序来响应它。这里上半部,就是快速处理,把网卡的数据读到内存中,更新一下硬件寄存器的状态,再发送一个软中断信号,通知下半部作进一步处理。下半部被软中断信号唤醒后,需要从内存中找到的网络数据,按照网络协议栈,逐层解析和处理,直到把它送到应用程序。
2. 查看软中断和内核线程
proc文件系统,是一种Linux内核空间和用户空间的交互的机制,可以用来查看内核的数据结构,或者动态修改内核配置。其中:
- /proc/softirqs提供软中断的运行情况;
- /proc/interrupts提供硬中断的运行情况。
$ cat /proc/softirqs
CPU0 CPU1
HI: 0 0
TIMER: 811613 1972736
NET_TX: 49 7
NET_RX: 1136736 1506885
BLOCK: 0 0
IRQ_POLL: 0 0
TASKLET: 304787 3691
SCHED: 689718 1897539
HRTIMER: 0 0
RCU: 1330771 1354737
从这个文件你可以看到软中断的10种类型和各种类型在不同CPU上的累计运行次数。比如:NET_RX,网络接收中断。NET_TX,网络发送中断。正常情况下,每种类型,在不同CPU上累计次数应该差不多,但也有例外。比如TASKLET,最常用的软中断实现机制,每个TASKLET运行一次就会结束,并且只在调用它的函数所在的CPU上运行。因此,这会导致调度的不均衡,更甚的会有性能限制。
使用命令:ps aux | grep ksoftorqd查看到内核线程的运行状态:
$ ps aux | grep softirq
root 7 0.0 0.0 0 0 ? S Oct10 0:01 [ksoftirqd/0]
root 16 0.0 0.0 0 0 ? S Oct10 0:01 [ksoftirqd/1]
注意,线程名有个中括号,说明ps无法获取它们的命令行参数,一般的像这种名字括在中括号中,就是内核线程。
3. 案例:软中断CPU使用率升高,怎么办?
在Linux中,当软中断事件频率过高时,内核线程也会因为CPU使用率过高,而导致软中断处理不及时,进而引发网络收发延迟,调度缓慢等性能问题。软中断CU使用率过高也是一种常见的性能问题。这里模拟一个SYN-FLOOD攻击场景:
这里要使用三个工具:sar、hping3、tcpdump
- sar是系统活动报告工具,即可以实时查看系统的当前活动,又可以配置保存和报告历史统计数据。
- hping3是一个可以构造TCP/IP协议数据包的工具,可以对系统进行安全审计、防火墙测试等。
- tcpdump网络抓包工具,用来分析各种网络问题。
# -S参数表示设置TCP协议的SYN(同步序列号),-p表示目的端口为80
# -i u100表示每隔100微秒发送一个网络帧
# 注:如果你在实践过程中现象不明显,可以尝试把100调小,比如调成10甚至1
$ hping3 -S -p 80 -i u100 192.168.0.30
在另一个终端操作系统的时候,发现系统相应明显变慢,即便敲个回车反应都很慢。
# top运行后按数字1切换到显示所有CPU
$ 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
...
从top输出,咋一看,是看不出什么问题的,但仔细一看,两个CPU的使用率只有3.3%、4.4%,但都是si即软中断上,从下面的进程列表看,%CPU虽然不高,但都是软中断进程ksoftirqd,猜测软中断有点可疑。可以查看/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
通过以上结果你会发现,NET_RX(网络接收)、SCHED(内核调度)、RCU(RCU锁)几个不停变化。其中,NET_RX变化最快,其他几个都是,是保证Linux调度、时钟和临界保护区这些工作正常运行所必需的,有变化也是正常。接下来从网络接收软中断着手,使用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
rxpck/s 和 txpck/s:每秒收发的网络帧数,也就是PPS。
rxkB/s 和 txkB/s:每秒收发的千字节数,也就是BPS。
很显然,eth0的收包个数或者字节数明显比发包大,计算一下,664 * 1024 / 12607 = 54字节,很小的网络帧。接下来可以用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
...
Flags [S]表示一个SYN包,再加上前面sar发现的PPS 12000的收包,可以确认这是SYN FLOOD 攻击。
以上是学习极客时间专栏(倪朋飞:Linux性能优化实战)的个人总结
来源:CSDN
作者:囚牢-峰子
链接:https://blog.csdn.net/qq_24436765/article/details/103665321