软中断

软中断

点完外卖后,平台虽会显示配送进度,但也不会傻盯着,得去干别的事情,等外卖到了配送员会通过「电话」通知,电话响了,就停下手中地事情,去拿外卖

中断是一种 异步事件处理机制,可以提高系统的并发处理能力

OS 收到中断请求,会打断其他进程的运行,中断处理程序,要尽可能快的执行完,减少对正常进程运行调度的影响

中断处理程序在响应中断时,可能还会「临时关闭中断」,意味着,如果当前中断处理程序没有执行完之前,系统中其他的中断请求都无法被响应,也就说中断有可能会丢失,所以中断处理程序要短且快

再以外卖为例,点了两份不同的外卖,由不同的配送员来配送

当第一份外卖送到时,配送员给我打了长长的电话,说了一些杂七杂八的事情,比如给个好评等等

如果这时另一位配送员也想给我打电话,因为我在通话中(相当于关闭了中断响应),自然就无法打通我的电话,他可能尝试了几次后就走掉了(相当于丢失了一次中断)

上半部/下半部

Linux 为解决中断处理程序执行过长和中断丢失的问题,将中断过程分成两个阶段,「上半部和下半部分」

  • 上半部用来快速处理中断,一般会暂时关闭中断请求,主要负责处理跟硬件紧密相关或者时间敏感的事情
  • 下半部用来延迟处理上半部未完成的工作,一般以「内核线程」的方式运行

前面的外卖例子,当接到第一位配送员的电话,可告诉配送员说我现在下楼,剩下等见面再说(上半部),然后就可挂断电话,到楼下后,再拿外卖,及跟配送员说其他的事情(下半部)

这样,第一位配送员就不会占用太多时间,当第二位配送员正好过来时,会有很大几率拨通电话

网卡接收网络包的例子

网卡收到网络包后,通过硬件中断通知内核有新数据到,内核调用对应中断处理程序来响应该事件,事件处理也分成上半部和下半部

上部分要快速处理,只把网卡数据读到内存,然后更新硬件寄存器状态

接着,内核触发软中断,较耗时且复杂的事情,交给「软中断处理程序」,也就是中断的下半部,从内存找到网络数据,按照网络协议栈,对网络数据进行逐层解析和处理,最后把数据送给应用程序

所以,中断处理程序的上部分和下半部可以理解为:

  • 上半部直接处理硬件请求,也就是硬中断,主要是负责耗时短的工作,特点是快速执行
  • 下半部是由内核触发,也就说软中断,主要是负责上半部未完成的工作,通常都是耗时比较长的事情,特点是延迟执行

硬中断(上半部)会打断 CPU 正在执行的任务,然后立即执行中断处理程序,软中断(下半部)以内核线程的方式执行,且每 CPU 对应一个软中断内核线程

软中断不只包括硬件设备中断处理程序的下半部,一些内核自定义事件也属于软中断,如内核调度等、RCU 锁等

查看中断

  • 软中断
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
cat /proc/softirqs
                    CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
          HI:          0          0          0          0          0          0          0          0
       TIMER:       3235        243       1748         86       7518        264       1329        140
      NET_TX:          0          0          0          0          0          0          0          0
      NET_RX:         20         32          0          3          8         42          4          9
       BLOCK:       2207          0        807          0          0          0          0          0
    IRQ_POLL:          0          0          0          0          0          0          0          0
     TASKLET:       2834          0        807          0          0          1          0          0
       SCHED:       3779        252       1750         89       7522        273       1322        143
     HRTIMER:          0          0          0          0          0          0          0          0
         RCU:       2910        236        643         75       7372        259       1197        118
  • 硬中断
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
  8:          0          0          0          0          0          0          0          0   IO-APIC   8-edge      rtc0
  9:          0          0          0          0          0          0          0          0   IO-APIC   9-fasteoi   acpi
NMI:          0          0          0          0          0          0          0          0   Non-maskable interrupts
LOC:         16         16          2         16         16         16         16         16   Local timer interrupts
SPU:          0          0          0          0          0          0          0          0   Spurious interrupts
PMI:          0          0          0          0          0          0          0          0   Performance monitoring interrupts
IWI:          0          0          0          0          0          0          0          0   IRQ work interrupts
RTR:          0          0          0          0          0          0          0          0   APIC ICR read retries
RES:       2250        709       2216        376        464        282        358        290   Rescheduling interrupts
CAL:        384        397        378        380        267        164        381        375   Function call interrupts
TLB:          0          0          0          0          0          0          0          0   TLB shootdowns
HYP:       2871         32        807          3          8         42          4          9   Hypervisor callback interrupts
HRE:          0          0          0          0          0          0          0          0   Hyper-V reenlightenment interrupts
HVS:       3295        297       1780        158       8912        312       1354        174   Hyper-V stimer0 interrupts
ERR:          0
MIS:          0
PIN:          0          0          0          0          0          0          0          0   Posted-interrupt notification event
NPI:          0          0          0          0          0          0          0          0   Nested posted-interrupt event
PIW:          0          0          0          0          0          0          0          0   Posted-interrupt wakeup event

这些数值是累计中断次数,大小没什么参考意义,中断次数的变化速率才是我们要关注的,可用 watch -d cat /proc/softirqs 查看中断次数的变化速率

软中断以内核线程方式执行,可用 ps -ef|grep softirq 看到内核线程,一般中括号内线线程都可以认为是内核线程

一般网络 I/O 比较高的 Web 服务器,NET_RX 中断变化速率相比其他中断类型快很多

sar -n DEV 查看网卡包接收速率情况,然后分析是哪个网卡有大量的网络包进来

再通过 tcpdump 抓包等,分析来源,非法的地址可考虑加防火墙,正常流量,要考虑硬件升级等