Docker,  Linux

Linux系统上的中断小结

一什么是中断

操作系统为了快速响应并处理硬件的请求,不得不中断当前正在执行的任务,转而优先去处理硬件的请求。比如,中断当前执行的任务(浏览网页),去处理打印机的打印请求。

二为什么要有中断

生活中点外卖的场景,你点完外卖该干嘛干嘛,配送员到了call你,你停下手中的工作,去取外卖。这个过程中,配送员给你打电话,你停下手中工作来响应取外卖,这其实就是一个中断。否则的话,你点完外卖,需要在门口一直候着,其它啥工作也不做,这种方式显然太低效不可取了。从某种意义上理解,中断是一种异步处理机制,提升了系统的并发处理能力。

三中断的特征和分类

1中断的特征

由于系统是中断当前正在执行的程序,转而去响应并处理中断程序的执行。那么就要求,中断处理程序要在尽可能短的时间内执行完成。

2为什么要分类

假如你定了2份儿外卖,由两个配送员配送,第一个到了,他call你,跟你沟通关于发票等相关事宜,持续几分钟时间。期间,第二个配送员也到了,此时他是无法call你的(智能电话可以切换接听新进电话不在讨论之中)。这不就麻烦了嘛,你一直处于占线状态,无法处理第2份外卖送达的请求。

为了解决这种问题,于是,你接到第一个电话就说,我知道外卖到了,马上来取,发票的事情,咱见面再谈。等第二个外卖员call你时,你依然可以正常响应。

于是,中断也是类似的,对于那些需要紧急马上短时间内可以处理并响应的事件,称为硬中断。它在中断禁止模式下运行,处理跟硬件紧密相关或事件敏感的工作。

那些可以异步的处理的事件,完成硬中断并没有全部完成的工作,就称为软中断

我知道外卖到了(硬中断),发票的事情(软中断)咱见面再聊。

3软中断:

查看方式:cat /proc/softirqs

4硬中断:

查看方式:cat /proc/interrupts

硬中断,通常执行快速,会打断CPU当前正在执行的任务,让CPU快速响应中断处理程序发起的请求;

软中断,通常是延迟执行,以内核线程的方式来执行,并且每个CPU都有一个软中断的内核线程,“ksoftirqd/cpu编号”。ps -ef|grep soft可以查看到。软中断包括网络收发、定时、调度、Read-Copy Update 锁等各种类型。

[root@ppasdev ~]# ps -ef|grep soft
root         4     2  0  2018 ?        00:26:59 [ksoftirqd/0]
root         9     2  0  2018 ?        00:21:04 [ksoftirqd/1]
root        13     2  0  2018 ?        00:15:14 [ksoftirqd/2]
root        17     2  0  2018 ?        00:13:26 [ksoftirqd/3]
root        21     2  0  2018 ?        00:14:25 [ksoftirqd/4]
root        25     2  0  2018 ?        00:09:39 [ksoftirqd/5]
root        29     2  0  2018 ?        00:12:32 [ksoftirqd/6]
root        33     2  0  2018 ?        00:07:54 [ksoftirqd/7]
root        37     2  0  2018 ?        00:10:39 [ksoftirqd/8]
root        41     2  0  2018 ?        00:06:48 [ksoftirqd/9]
root        45     2  0  2018 ?        00:09:35 [ksoftirqd/10]
root        49     2  0  2018 ?        00:06:19 [ksoftirqd/11]
root        53     2  0  2018 ?        00:14:43 [ksoftirqd/12]
root        57     2  0  2018 ?        00:07:18 [ksoftirqd/13]
root        61     2  0  2018 ?        00:10:57 [ksoftirqd/14]
root        65     2  0  2018 ?        00:05:56 [ksoftirqd/15]
root        69     2  0  2018 ?        00:08:11 [ksoftirqd/16]
root        73     2  0  2018 ?        00:05:19 [ksoftirqd/17]
root        77     2  0  2018 ?        00:07:42 [ksoftirqd/18]
root        81     2  0  2018 ?        00:05:04 [ksoftirqd/19]
root        85     2  0  2018 ?        00:07:21 [ksoftirqd/20]
root        89     2  0  2018 ?        00:04:58 [ksoftirqd/21]
root        93     2  0  2018 ?        00:07:26 [ksoftirqd/22]
root        97     2  0  2018 ?        00:04:41 [ksoftirqd/23]
root     16182  9301  0 09:02 pts/2    00:00:00 grep soft
You have new mail in /var/spool/mail/root
[root@ppasdev ~]# 

补充:ps或者是top看到的进程,进程名被[]包裹的,通常都是内核线程,无法查看其完整的执行命令名。

另外,我们也可以看到每个CPU对应的软中断的内核线程,其父进程都是2号进程,该进程是【kthreadd】。

[root@node-1 ~]# ps -ef|grep 2
root         1     0  0 3月29 ?       00:09:13 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root         2     0  0 3月29 ?       00:00:01 [kthreadd]
root         3     2  0 3月29 ?       00:07:23 [ksoftirqd/0]
root         5     2  0 3月29 ?       00:00:00 [kworker/0:0H]

四网络收发数据场景的中断

网卡的请求处理,既包含硬中断也有软中断。数据包来了,立即通知CPU,这是硬中断,然后才是接收和处理数据包,这便是软中断。进而,可以解释,为什么大量的体积小的网络数据包,会带来性能问题呢,就是这个原因。频繁的中断打断CPU,然后开始执行接收处理数据包的工作。

简单理解,中断,其实是内核对进程的一种保护机制。

0 准备工作

两台Linux机器, 172.16.11.168作为server端,172.16.11.148作为客户端。都安装Docker、tcpdump、sysstat工具包。

1 server端启动NGINX容器

[root@master-node ~]# docker run -itd --name=nginx -p 80:80 nginx
Unable to find image 'nginx:latest' locally
Trying to pull repository docker.io/library/nginx ... 
latest: Pulling from docker.io/library/nginx
1fe172e4850f: Pull complete 
35c195f487df: Pull complete 
213b9b16f495: Pull complete 
a8172d9e19b9: Pull complete 
f5eee2cb2150: Pull complete 
93e404ba8667: Pull complete 
Digest: sha256:859ab6768a6f26a79bc42b231664111317d095a4f04e4b6fe79ce37b3d199097
Status: Downloaded newer image for docker.io/nginx:latest
30bad7a0219ad738aa512c4c131ce45de6f22e8d7b80dd771e50e6452830e651
[root@master-node ~]

2 client通过hping3向server发送大量的小包网络数据

[root@node-1 ~]# curl http://172.16.11.168
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
[root@node-1 ~]# hping3 -S -p 80 u100 172.16.11.168
...

其中: -S参数表示设置TCP协议的SYN(同步序列号),-p表示目的端口为80, -i u100表示每隔100微秒发送一个网络帧,具体可以通过hping3 -h来查看使用帮助。

3 查看服务端性能指标

[root@master-node ~]# top
top - 08:51:28 up 626 days, 21:30,  3 users,  load average: 0.55, 0.36, 0.31
Tasks: 218 total,   2 running, 214 sleeping,   0 stopped,   2 zombie
%Cpu(s):  5.0 us,  2.3 sy,  0.0 ni, 71.7 id,  0.1 wa,  0.0 hi, 21.0 si,  0.0 st
KiB Mem :  8175440 total,   225444 free,  5852896 used,  2097100 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  1473044 avail Mem 
​
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                                                                                  
 2737 root      20   0 1190756 386880  29116 S  14.0  4.7  14901:25 kube-apiserver                                                                                                                                           
14711 root      20   0 1991604  88336  19576 S   6.3  1.1   9937:31 kubelet                                                                                                                                                  
 2132 root      20   0 10.697g  64292  12972 S   5.0  0.8   4907:48 etcd                                                                                                                                                     
 8728 root      20   0  827324  67544  15348 S   3.7  0.8   1194:07 kube-controller                                                                                                                                          
12929 root      20   0 1651168  63284   9616 S   3.0  0.8   3488:49 dockerd-current                                                                                                                                          
   23 root      20   0       0      0      0 S   2.7  0.0  70:42.55 ksoftirqd/3                                                                                                                                              
    3 root      20   0       0      0      0 R   1.3  0.0   8:38.06 ksoftirqd/0                                                                                                                                              
   13 root      20   0       0      0      0 S   1.3  0.0   8:29.64 ksoftirqd/1         

此时,可以看到系统的软中断CPU使用率涨上来了,达到20%多,同时看到进程列表里有软中断进程(ksoftirqd/0、ksoftirqd/1、ksoftirqd/3)占有系统资源。

4 dstat查看系统性能指标

[root@master-node ~]# dstat 
You did not select any stats, using -cdngy by default.
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw 
  2   4  94   0   0   0|2865k   27k|   0     0 |  22B   22B| 409  1526 
  4   2  80   0   0  15|   0    30k|1408k 1734k|   0     0 |  22k 6120 
  4   1  81   0   0  14|   0    12k|1385k 1716k|   0     0 |  22k 5918 
  6   2  78   0   0  13|   0    28k|1371k 1688k|   0     0 |  22k 6217 
  2   1  83   0   0  14|   0     0 |1340k 1658k|   0     0 |  22k 6247 
  4   2  79   0   0  15|   0    82k|1409k 1735k|   0     0 |  23k 7273 
  9   4  69   0   0  17|   0     0 |1395k 1718k|   0     0 |  22k 8308 
  9   4  66   0   0  21|   0    91k|1376k 1693k|   0     0 |  20k 8564 
  9   1  69   0   0  20|   0     0 |1380k 1699k|   0     0 |  19k 5851 
 11   4  61   0   0  24|  32k  448k|1382k 1702k|   0     0 |  20k 9391 
 10   3  67   0   0  19|   0    52k|1405k 1733k|   0     0 |  20k 8145 
  4   1  78   0   0  16|   0    28k|1412k 1739k|   0     0 |  23k 7339 
  4   2  74   0   0  19|   0    46k|1357k 1681k|   0     0 |  21k 7587 
  3   1  81   0   0  14|   0     0 |1389k 1710k|   0     0 |  23k 6308 
^C[root@master-node ~]# 

同样,此时看到系统软中断的CPU使用率维持17%左右,同时,可以看到网络的流入流出量比较大。

我们判断出系统的软中断占用了比较明显的CPU资源,那么到底是哪一类软中断占用了CPU资源呢?我们可以通过watch -d cat /proc/softirqs来观测软中断的变化,其中watch -d表示观测动态变化的部分,并且会高亮显示。

5 观测软中断变化率/proc/softirqs

Every 2.0s: cat /proc/softirqs                                                                                                                                                                        Tue May 10 09:02:38 2022
​
                    CPU0       CPU1       CPU2       CPU3
          HI:          0          0          0          0
       TIMER: 2672518579 2647468403 2431745598 2558594737
      NET_TX:        352   10833273        371        333
      NET_RX:  515094643  446562848  759935086  435055629
       BLOCK:   63459234   10831408   34464900  555490751
BLOCK_IOPOLL:          0          0          0          0
     TASKLET:     797639    1134312    1504795    2253722
       SCHED: 1560074575 1518308323 1388392141 1486880062
     HRTIMER:          0          0          0          0
         RCU: 1446535727 1445120992 1404463822 1436449926

这里,可以看到系统额NET_RX,网络收包的软中断变化最大。其它几个软中断指标变化不是特别明显。

6 sar -n DEV 1监控网络流量变化

[root@master-node ~]# sar -n DEV 1
09时11分26秒     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
09时11分27秒 vethd3c10b0      0.00      0.00      0.00      0.00      0.00      0.00      0.00
09时11分27秒 veth7222006      0.00      0.00      0.00      0.00      0.00      0.00      0.00
09时11分27秒 veth9134df2      0.00      0.00      0.00      0.00      0.00      0.00      0.00
09时11分27秒 veth0212667   6375.00  12751.00    361.08    672.42      0.00      0.00      0.00
09时11分27秒        lo    122.00    122.00     22.10     22.10      0.00      0.00      0.00
09时11分27秒 virbr0-nic      0.00      0.00      0.00      0.00      0.00      0.00      0.00
09时11分27秒    virbr0      0.00      0.00      0.00      0.00      0.00      0.00      0.00
09时11分27秒 veth7fd5d21      0.00      0.00      0.00      0.00      0.00      0.00      0.00
09时11分27秒    ens160  12765.00   6378.00    750.80    362.66      0.00      0.00      0.00
09时11分27秒 flannel.1      0.00      0.00      0.00      0.00      0.00      0.00      0.00
09时11分27秒   docker0   6376.00  12751.00    273.97    672.42      0.00      0.00      0.00
​
平均时间:     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
平均时间: vethd3c10b0      0.00      0.00      0.00      0.00      0.00      0.00      0.00
平均时间: veth7222006      0.00      0.00      0.00      0.00      0.00      0.00      0.00
平均时间: veth9134df2      0.00      0.00      0.00      0.00      0.00      0.00      0.00
平均时间: veth0212667   6355.20  12710.32    359.96    670.27      0.00      0.00      0.00
平均时间:        lo    134.77    134.77     23.47     23.47      0.00      0.00      0.00
平均时间: virbr0-nic      0.00      0.00      0.00      0.00      0.00      0.00      0.00
平均时间:    virbr0      0.00      0.00      0.00      0.00      0.00      0.00      0.00
平均时间: veth7fd5d21      0.00      0.00      0.00      0.00      0.00      0.00      0.00
平均时间:    ens160  12741.69   6372.33    751.24    367.56      0.00      0.00      0.00
平均时间: flannel.1      0.00      0.00      0.00      0.00      0.00      0.00      0.00
平均时间:   docker0   6355.20  12710.33    273.07    670.27      0.00      0.00      0.00
[root@master-node ~]# 

从上,可以看到ens160这块网卡接收数据包个数rxpck/s是12741个,发送数据包个数txpck/s是6372,接收数据包大小rxKB/s为751,发送数据包大小367KB/s。折算下来,平均每秒接收的每个数据包大小为751*1024/12741≈60 bytes。也就是我们常说的网络小包。

同时,看到另外两块网卡docker0和veth0212667的网络收发数据流量方向正好和ens160网卡设备相反,数据量大小基本保持一致。这其实是server端的物理网卡接收到网络流量之后,转发给Docker容器的网卡设备。

7 tcpdump网络抓包分析

[root@master-node ~]# tcpdump -i ens160 -n tcp port 80
...
09:13:10.121181 IP 172.16.11.148.61312 > 172.16.11.168.http: Flags [R], seq 32336669, win 0, length 0
09:13:10.121218 IP 172.16.11.148.61316 > 172.16.11.168.http: Flags [S], seq 101696433, win 512, length 0
09:13:10.121230 IP 172.16.11.148.61314 > 172.16.11.168.http: Flags [R], seq 214645300, win 0, length 0
09:13:10.121329 IP 172.16.11.148.61315 > 172.16.11.168.http: Flags [R], seq 511517631, win 0, length 0
09:13:10.121332 IP 172.16.11.148.61313 > 172.16.11.168.http: Flags [R], seq 1262824714, win 0, length 0
09:13:10.121363 IP 172.16.11.148.61317 > 172.16.11.168.http: Flags [S], seq 1170847465, win 512, length 0
09:13:10.121415 IP 172.16.11.168.http > 172.16.11.148.61316: Flags [S.], seq 181639977, ack 101696434, win 29200, options [mss 1460], length 0
09:13:10.121450 IP 172.16.11.168.http > 172.16.11.148.61317: Flags [S.], seq 952647435, ack 1170847466, win 29200, options [mss 1460], length 0
09:13:10.121649 IP 172.16.11.148.61319 > 172.16.11.168.http: Flags [S], seq 793001380, win 512, length 0
09:13:10.121650 IP 172.16.11.148.61318 > 172.16.11.168.http: Flags [S], seq 49059466, win 512, length 0
09:13:10.121666 IP 172.16.11.148.61316 > 172.16.11.168.http: Flags [R], seq 101696434, win 0, length 0
09:13:10.121747 IP 172.16.11.168.http > 172.16.11.148.61318: Flags [S.], seq 940527943, ack 49059467, win 29200, options [mss 1460], length 0
09:13:10.121817 IP 172.16.11.168.http > 172.16.11.148.61319: Flags [S.], seq 2772151625, ack 793001381, win 29200, options [mss 1460], length 0^C
​
29465 packets captured
77060 packets received by filter
47427 packets dropped by kernel
[root@master-node ~]#

从中,看到网络数据包的来源主要是172.16.11.148。

五小结

通过一个hping3的客户端模拟向服务器的NGINX持续发送小网络数据包,可以引起服务器端的软中断的CPU使用率上升。进一步分析的去看,是属于软中断中的网络接收数据的中断程序引起的。

如果案例中的软中断CPU不明显的话,可以把hping3发送数据的频率再进一步缩小。比如:hping3 -S -p 80 -i u10 172.16.11.168

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

六参考

倪朋飞老师Linux性能优化实战,第10 | 案例篇:系统的软中断CPU使用率升高,我该怎么办?

留言