3. /proc/interrupts 详解:如何查看中断统计、识别网卡中断、理解中断号与CPU分布

/proc/interrupts 是 Linux 内核暴露给用户空间的中断统计虚拟文件,它实时记录了系统中每个 IRQ(中断请求)号在每一个 CPU 核心上的触发次数。对于网络性能优化而言,这个文件是诊断中断分布不均、验证亲和性配置是否生效的第一手数据源。

核心认知: 在 SMP(对称多处理)系统中,/proc/interrupts 的每一列对应一个 CPU 核心,每一行对应一个中断源。通过观察各列数值的差异,可以快速判断是否存在“中断扎堆”现象。

3.1 文件结构速览:列与行的含义

执行 cat /proc/interrupts 后,输出通常包含以下结构(以 4 核 CPU 为例):

           CPU0       CPU1       CPU2       CPU3
  0:         45          0          0          0   IO-APIC   2-edge      timer
  1:         10          0          0          0   IO-APIC   1-edge      i8042
  8:          1          0          0          0   IO-APIC   8-edge      rtc0
 24:         0          0          0          0   PCI-MSI   327680-edge  enp3s0
 25:         0          0          0          0   PCI-MSI   327681-edge  enp3s0-rx-0
 26:         0          0          0          0   PCI-MSI   327682-edge  enp3s0-tx-0
 27:     123456     234567     345678     456789   PCI-MSI   327683-edge  enp3s0-rx-1
NMI:          0          0          0          0   Non-maskable interrupts
LOC:   12345678   23456789   34567890   45678901   Local timer interrupts
字段位置 名称 说明
第 1 列 IRQ 号 中断请求编号,内核唯一标识一个中断源
第 2~N 列 CPU 统计 每个 CPU 核心处理该中断的累计次数
倒数第 3 列 中断控制器类型 IO-APIC、PCI-MSI、PCI-MSI-X 等
倒数第 2 列 中断触发信息 中断号/触发方式(edge/level)
最后一列 设备名称 注册该中断的驱动或设备描述
关键识别点: 网卡多队列(RSS)启用后,每个队列会拥有独立的 IRQ 号,命名通常包含 -rx-(接收队列)和 -tx-(发送队列)后缀,例如 enp3s0-rx-1。

3.2 如何精准识别网卡中断

在大量中断行中快速定位网卡设备,推荐以下三种方法:

  1. 设备名匹配法: 直接搜索网卡接口名(如 eth0、enp3s0),现代驱动通常会在最后一列显式标注。
  2. MSI 类型过滤法: 网卡多队列中断几乎全部使用 PCI-MSI 或 PCI-MSI-X 类型,过滤倒数第三列可缩小范围。
  3. 数值波动观察法: 在高流量场景下,网卡中断对应的 CPU 统计列会快速递增,而其他设备(如定时器、键盘)增长缓慢。
# 快速过滤网卡相关中断(以 enp3s0 为例)
grep -E "enp3s0|eth0" /proc/interrupts

# 仅显示 PCI-MSI 类型的中断
grep "PCI-MSI" /proc/interrupts

# 观察每秒中断增长率(需安装 sysstat)
watch -n 1 'cat /proc/interrupts | grep enp3s0'

3.3 中断号与 CPU 分布的可视化分析

下面这张 SVG 图展示了 4 核系统上,一个 4 队列网卡的中断分布情况。理想状态下,每个队列的中断应均匀散布在不同 CPU 上;而实际生产环境中,经常出现所有队列中断集中在 CPU0 的“扎堆”现象。

网卡多队列中断 CPU 分布示意图 网卡多队列中断 CPU 分布示意图 网卡 enp3s0 4 队列 队列 0 IRQ 24 队列 1 IRQ 25 队列 2 IRQ 26 队列 3 IRQ 27 CPU0 中断: 0 CPU1 中断: 0 CPU2 中断: 0 CPU3 中断: 456789 ⚠ 问题说明 所有队列中断 全部映射到 CPU0 导致 CPU0 负载飙升 其他 CPU 空闲 理想分布: 队列0→CPU0 队列1→CPU1 队列2→CPU2 队列3→CPU3

3.4 实战:从 /proc/interrupts 诊断中断失衡

以下是一个真实生产环境的诊断案例。通过对比“优化前”和“优化后”的中断统计,可以直观看到亲和性调整带来的效果。

指标 优化前(中断扎堆) 优化后(均匀分布) 说明
CPU0 中断数 1,234,567 308,641 下降 75%
CPU1 中断数 12 308,640 恢复正常参与
CPU2 中断数 8 308,642 恢复正常参与
CPU3 中断数 5 308,644 恢复正常参与
软中断 CPU0 占比 98% 25% 瓶颈消除
网卡吞吐量 4.2 Gbps 9.8 Gbps 提升 133%
⚠ 常见误区: 不要只看中断总数!即使总中断数很大,如果均匀分布在所有 CPU 上,系统依然健康。真正的“失衡”标志是:某个 CPU 的中断计数远高于其他 CPU 的 中位数,且该 CPU 的 /proc/stat 中 softirq 时间占比超过 60%。

3.5 进阶:通过 smp_affinity 验证中断绑定

每个 IRQ 号对应的 CPU 亲和性掩码存储在 /proc/irq/{IRQ_NUM}/smp_affinity 中。读取该文件可以验证当前中断是否被正确绑定到目标 CPU。

# 查看 IRQ 27 的当前 CPU 亲和性掩码
cat /proc/irq/27/smp_affinity
# 输出示例:00000000,00000000,00000000,00000008
# 表示绑定到 CPU3(bit 3 置位)

# 查看 IRQ 27 的有效 CPU 列表(更易读)
cat /proc/irq/27/smp_affinity_list
# 输出示例:3

smp_affinity 使用十六进制位图表示 CPU 集合,而 smp_affinity_list 使用十进制 CPU 编号列表。两者指向同一个内核控制位,只是展示格式不同。

最佳实践: 在调整亲和性前后,分别执行 cat /proc/interrupts | grep enp3s0 并对比各 CPU 列的增长速率。如果调整后所有队列的中断数在多个 CPU 上同步增长,说明绑定生效;如果仍然集中在单个 CPU,需要检查 BIOS 设置或 irqbalance 是否覆盖了手动配置。