Linux软中断
进程的不可中断状态是系统的一种保护机制,可以保证硬件的交互过程不被意外打断。所以,短时间的不可中断状态是很正常的。
中断是系统用来响应硬件设备请求的一种机制,它会打断进程的正常调度和执行,然后调用内核中的中断处理程序来响应设备的请求。
中断其实是一种异步的事件处理机制,可以提高系统的并发处理能力。由于中断处理程序会打断其他进程的运行。所以,为了减少对正常进程调度的影响,中断处理程序就需要尽可能快地运行。如果中断本身要做的事情不多,那么处理起来也不会有太大问题。但是如果中断要处理的事情很多,中断服务程序就有可能要运行很长时间。
特别是,中断处理程序在响应中断时,还会临时关闭中断。这就会导致上一次中断处理完成之前,其他中断都不能响应,也就是说中断有可能会丢失。
Linux将中断处理过程分成了两个阶段:上半部和下半部
上半部:硬中断,快速执行。用来快速处理中断,它在中断禁止模式下运行,主要处理跟硬件紧密相关的事件或时间敏感的工作。
下半部:软中断,延迟执行。用来延迟上半部未完成的工作,通常以内核线程的方式运行。
Linux中的软中断包括网络收发,定时,调度,RCU锁等各种类型,可以通过查看/proc/softirqs来观察软中断的运行情况。
事例:网卡接收数据
网卡接收到数据包后,会通过硬件中断的方式,通知内核有新的数据到了。这时,内核就应该调用中断处理程序来响应它。你可以自己先想一下,这种情况下的上半部和下半部分别负责什么工作呢?
对上半部来说,既然是快速处理,其实就是要把网卡的数据读到内存中,然后更新一下硬件寄存器的状态(表示数据已经读好了),最后再发送一个软中断信号,通知下半部做进一步的处理。而下半部被软中断信号唤醒后,需要从内存中找到网络数据,再按照网络协议栈,对数据进行逐层解析和处理,直到把它送给应用程序。
实际上,上半部会打断CPU正在执行的任务,然后立即执行中断处理程序。而下半部以内核线程的方式执行,并且每个CPU都对应一个软中断内核线程,名字为“ksoftirqd/CPU编号”,比如说,0号CPU对应的软中断内核线程的名字就是ksoftirqd/0。不过要注意的是,软中断不只包括了刚刚所讲的硬件设备中断处理程序的下半部,一些内核自定义的事件也属于软中断,比如内核调度和RCU锁(Read-Copy Update的缩写,RCU是Linux内核中最常用的锁之一)等。
查看软中断和内核线程
通过proc文件系统查看相关信息,proc它是一种内核空间和用户空间进行通信的机制。可以用来查看内核的数据结构,或者用来动态修改内核的配置。其中:
/proc/softirqs 提供了软中断的运行情况;
/proc/interrupts 提供了硬中断的运行情况;
查看/proc/softirqs文件内容时,你要特别注意以下这两点:
第一,第一列的是软中断的类型,从第一列可以看到,软中断包括了10个类别,分别对应不同的工作类型。
第二,同一种软中断在不同的CPU上的分布情况,也就是同一行的内容。正常情况下,同一种中断在不同CPU上累积次数应该差不多。
不过TASKLET在不同CPU上的分布并不均匀。TASKLET是最常用的软中断实现机制,每个TASKLET只运行一次就会结束,并且只在调用它的函数所在的CPU上运行。
另外,软中断实际上是以内核线程的方式运行的,每个CPU都对应一个软中断内核线程。这个软中断内核线程就叫做ksoftirqd/CPU编号。接下来我们查看这些线程的运行情况:
注意:这些线程的名字外面都有中括号,这说明PS无法获取它们的命令行参数(cmline)。一般来说,ps的输出中,名字括在中括号里的,一般都是内核线程。
当软中断事件的频率过高时,内核线程也会因为CPU使用率过高而导致软中断处理不及时,进而引发网络收发延迟,调度缓慢等性能问题。软中断CPU使用率过高也是一种最常见的性能问题。
案例:
工具安装 docker,sysstat,sar,hping3,tcpdump等工具
工具介绍:
sar 是一个系统活动报告工具,既可以实时查看系统的当前活动,又可以配置保存和报告历史统计数据。
hping3是一个可以构造TCP/IP协议数据包的工具,可以对系统进行安全审计、防火墙测试等。
tcpdump是一个常用的网络抓包工具,常用来分析各种网络问题。
其中一台虚拟机运行Nginx,用来模拟待分析的Web服务器;而另一台当作Web服务器的客户端,用来给Nginx增加压力请求。使用两台虚拟机的目的,是为了相互隔离,避免“交叉感染”。
接下来,我们打开两个终端,分别SSH登录到两台机器上,并安装上面提到的这些工具。
操作和分析
第一个终端运行docker
第二个终端,使用curl访问Nginx监听的端口,确认Nginx正常启动。假设192.168.0.30是Nginx所在虚拟机的IP地址,运行curl命令后你应该会看到下面这个输出界面:
此时进入第一个终端,运行Shell时都明显感觉到变慢了。会有卡顿的现像了。没有就再加强一点。hping3的发送频率。先查看一下系统的整体资源情况。TOP
从输出看,CPU使用率都不高。但从进程列表上也可以看到,CPU使用率最高的是软中断进程ksoftirqd。有可能是软中断的问题。这里查看/proc/softirqs文件内容并不能看出什么。因为/proc/softirqs文件记录的是系统运行以来的累积中断次数。所以我们直接看文件内容,得到的只是累积中断次数。对这里的问题并没有直接参考意义。中断次数的变化速率才是我们需要关注的。此时可以使用 watch命令来帮助查看变化的信息。
通过/proc/softirqs文件内容的变化情况,你可以发现,TIMER(定时中断)、NET_RX(网络接收)、SCHED(内核调度)、RCU(RCU锁)等这几个软中断都在不停变化。其中,NET_RX,也就是网络数据包接收软中断的变化速率最快。而其他几种类型的软中断,是保证 Linux调度、时钟和临界区保护这些正常工作所必需的,所以它们有一定的变化倒是正常的。那么接下来,我们就从网络接收的软中断着手,继续分析。既然是网络接收的软中断,第一步应该就是观察系统的网络接收情况。这里你可能想起了很多网络工具,不过,今天使用工具sar。
sar可以用来查看系统的网络收发情况,还有一个好处是,不仅可以观察网络收发的吞吐量(BPS,每秒收发的字节数),还可以观察网络收发的PPS,即每秒收发的网络帧数我们在第一个终端中运行sar命令,并添加-n DEV参数显示网络收发的报告:
对于sar的输出界面,我先来简单介绍一下,从左往右依次是:
第一列:表示报告的时间。
第二列:IFACE表示网卡
第三、四列:rxpck/s和 txpck/s分别表示每秒接收、发送的网络帧数,也就是PPS。
第五、六列:rxkB/s和txkB/s分别表示每秒接收、发送的千字节数,也就是BPS。
后面的其他参数基本接近0,显然跟今天的问题没有直接关系,你可以先忽略掉。
我们具体来看输出的内容,计算出平均每个网络帧大小。
每秒发送PBS * 1024/每秒发送PPS=平均每个网络帧大小
2382*1024/40640=60
这里平均帧大小为60字节,这显然是很小的网络帧,应该就是小包问题。
接下来使用抓包工具tcpdump命令,通过 -i eth0,并通过tcp port 80 选项指定TCP协议的80端口。查找包来源,封掉来源IP。