这篇文章上次修改于 899 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

中断处理程序响应中断时,会临时关闭中断。导致上一次中断处理完成之前不会响应别的中断,导致中断丢失。

Linux 将中断分成了上下两半部:

  • 上半部直接处理硬件请求,为硬中断,特点是快速执行。
  • 下半部由内核触发,为软中断,特点是延迟执行。

查看软中断和内核线程

/proc/softirqs 提供了软中断运行情况。

/proc/interrupts 提供了硬中断运行情况。

查看各种类型的软中断在不同 CPU 上的累积运行次数:

$ cat /proc/softirqs
                    CPU0
          HI:          1
       TIMER: 1026316871
      NET_TX:          0  # 网络发送中断
      NET_RX:   61775356  # 网络接收中断
       BLOCK:   40798866
BLOCK_IOPOLL:          0
     TASKLET:         16
       SCHED:          0
     HRTIMER:          0
         RCU: 1131073805

Linux 中的软中断包括网络收发,定时,调度、RCU 锁等类型。

查看软中断线程:

$ ps aux | grep softirq
root         6  0.0  0.0      0     0 ?        S    4月03   5:06 [ksoftirqd/0]
root      1435  0.0  0.0 112828   972 pts/0    D+   16:23   0:00 grep --color=auto softirq

软中断是以内核线程方式运行的,每个 CPU 都对应一个软中断线程。

软中断CPU使用率升高怎么办?

当发现系统响应变慢时,需要用 top 查看下系统资源情况:

# 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
...

会发现,CPU 使用率不高,负载不高。但是 CPU 的使用率主要在软中断,且进程中 CPU 利用率最高的是软中断进程。所以接下来查看下软中断:

$ 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

可以看到,网络接收中断变化最快,所以接下来查看网络,可用 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

其中:

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

可见,eth0 的 rxpck/s 较大,而 rxkB/s 较小,平均每个网络帧只有 664*1024/12607 = 5456 字节,说明接收的包是小包,需要查看该包到底是什么。可通过 tcpdump 在 eth0 上抓包分析:

# -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 包,可以确认,这是 192.168.0.2 发来的 SYN FLOOD 攻击,需将该 IP 禁掉。

参考

倪朋飞. Linux 性能优化实战.