Red Hat Training

A Red Hat training course is available for RHEL 8

34.2. 调优 IRQ 平衡

在多核主机上,您可以通过确保 Red Hat Enterprise Linux 平衡中断队列(IRQ)来在 CPU 核之间分发中断来提高性能。

34.2.1. 中断和中断处理程序

当网络接口控制器(NIC)接收传入数据时,它会使用直接内存访问(DMA)将数据复制到内核缓冲区中。然后,NIC 通过触发一个硬中断来向内核通知此数据。这些中断是由中断处理程序处理的,这些处理程序只做最少的工作,因为它们已中断了另一个任务,处理程序不能中断自己。硬中断在 CPU 使用率方面可能代价高昂,特别是在使用内核锁时。

然后,硬中断处理器将大多数接收的数据包留给软件中断请求(SoftIRQ)进程。内核可以更公平地调度这些进程。

例 34.1. 显示硬件中断

内核将中断计数存储在 /proc/interrupts 文件中。要显示特定 NIC 的计数,如 enp1s0,请输入:

# egrep "CPU|enp1s0" /proc/interrupts
         CPU0     CPU1     CPU2    CPU3    CPU4   CPU5
 105:  141606        0        0       0       0      0  IR-PCI-MSI-edge      enp1s0-rx-0
 106:       0   141091        0       0       0      0  IR-PCI-MSI-edge      enp1s0-rx-1
 107:       2        0   163785       0       0      0  IR-PCI-MSI-edge      enp1s0-rx-2
 108:       3        0        0  194370       0      0  IR-PCI-MSI-edge      enp1s0-rx-3
 109:       0        0        0       0       0      0  IR-PCI-MSI-edge      enp1s0-tx

每个队列在分配给它的第一列中有一个中断向量。当系统引导时,或者用户载入 NIC 驱动程序模块时,内核会初始化这些向量。会给每个接收(RX)和传输(TX)队列分配一个唯一的向量,其告知中断处理程序中断来自哪个 NIC 或队列。列代表每个 CPU 核的传入中断数。

34.2.2. 软件中断请求

软件中断请求(SoftIRQ)清除网络适配器的接收环缓冲。内核调度 SoftIRQ 例程在其他任务没有被中断的时侯运行。在 Red Hat Enterprise Linux 上,名为 ksoftirqd/cpu-number 的进程运行这些例程,并调用特定于驱动程序的代码函数。

要监控每个 CPU 内核的 SoftIRQ 计数,请输入:

# watch -n1 'egrep "CPU|NET_RX|NET_TX" /proc/softirqs'
                    CPU0       CPU1	  CPU2       CPU3	CPU4	   CPU5       CPU6	 CPU7
      NET_TX:	   49672      52610	 28175      97288      12633	  19843      18746     220689
      NET_RX:         96       1615        789         46         31	   1735       1315     470798

命令会动态更新输出。按 Ctrl+C 中断输出。

34.2.3. NAPI 轮询

新的 API (NAPI)是设备驱动程序数据包处理框架的扩展,以提高传入网络数据包的效率。硬中断非常昂贵,因为它们通常会导致上下文从内核空间切换到用户空间,然后再切换回来,并且不能中断自己。即使中断合并,中断处理器也会完全垄断一个 CPU 核。使用 NAPI ,驱动程序可以使用轮询模式,而不是内核为接收的每个数据包进行硬中断。

在正常操作下,内核会发出一个初始硬中断,后跟一个软中断请求(SoftIRQ)处理程序,该处理程序使用 NAPI 例程轮询网卡。为防止 SoftIRQ 垄断一个 CPU 核,轮询例程有一个确定 SoftIRQ 可以使用的 CPU 时间的预算。完成 SoftIRQ 轮询例程后,内核会退出例程,并将其安排在稍后运行,以重复从网卡接收数据包的过程。

34.2.4. irqbalance 服务

在具有和不具有非统一内存访问(NUMA)架构的系统上,irqbalance 服务根据系统状况有效地平衡跨 CPU 核的中断。irqbalance 服务在后台运行,每 10 秒监控一次 CPU 负载。当 CPU 的负载过高时,服务会将中断移到其他 CPU 核。因此,该系统表现良好,并更有效地处理负载。

如果 irqbalance 没有运行,则 CPU 核 0 通常会处理大多数中断。即使在中等负载下,这个 CPU 核可能会变得非常忙碌,试图处理系统中所有硬件的工作负载。因此,中断或基于中断的工作可能会丢失或延迟。这可能导致网络和存储性能较低、数据包丢失以及其他潜在的问题。

重要

禁用 irqbalance 可能会对网络吞吐量造成负面影响。

在只有一个 CPU 核的系统上,irqbalance 服务不提供任何好处,并自行退出。

默认情况下,irqbalance 服务在 Red Hat Enterprise Linux 上启用并运行。要重新启用该服务(如果您禁用了它),请输入:

# systemctl enable --now irqbalance

34.2.5. 增加 SoftIRQ 可在 CPU 上运行的时间

如果 SoftIRQ 没有运行足够长时间,则传入数据的速度可能会超过内核快速排空缓冲区的能力。因此,网络接口控制器(NIC)缓冲区溢出,数据包丢失。

如果 softirqd 进程无法在一个 NAPI 轮询周期中检索来自接口的所有数据包,则表示 SoftIRQ 没有足够的 CPU 时间。这种情况可能出现在具有快速 NIC 的主机上,如 10 Gbps 和更快。如果您增加了 net.core.netdev_budgetnet.core.netdev_budget_usecs 内核参数的值,则您可以控制 softirqd 在一个轮询周期内处理数据包的时间和数量。

流程

  1. 要确定是否需要调整 net.core.netdev_budget 参数,请显示 /proc/net/softnet_stat 文件中的计数:

    # awk '{for (i=1; i<=NF; i++) printf strtonum("0x" $i) (i==NF?"\n":" ")}' /proc/net/softnet_stat | column -t
    221951548  0  0      0  0  0  0  0  0  0  0  0  0
    192058677  0  20380  0  0  0  0  0  0  0  0  0  1
    455324886  0  0      0  0  0  0  0  0  0  0  0  2
    ...

    awk 命令将 /proc/net/softnet_stat 中的值从十六进制转换为十进制格式,并以表格式显示它们。每行代表核 0 开始的 CPU 核。

    相关的列有:

    • 第一列:收到的总帧数。
    • 第三列:softirqd 进程不能在一个 NAPI 轮询周期中检索来自接口的所有数据包的次数。
    • 最后一列:CPU 核号。
  2. 如果 /proc/net/softnet_stat 文件的第三列中的计数随着时间而递增,请调优系统:

    1. 显示 net.core.netdev_budget_usecsnet.core.netdev_budget 参数的当前值:

      # sysctl net.core.netdev_budget_usecs net.core.netdev_budget
      net.core.netdev_budget_usecs = 2000
      net.core.netdev_budget = 300

      使用这些设置,softirqd 进程在一个轮询周期内最多有 2000 微秒来处理最多 300 个来自 NIC 的消息。轮询根据首先满足哪个条件而结束。

    2. 使用以下内容创建 /etc/sysctl.d/10-netdev_budget.conf 文件:

      net.core.netdev_budget = 600
      net.core.netdev_budget_usecs = 4000

      将参数设置为其当前值的两倍。

    3. /etc/sysctl.d/10-netdev_budget.conf 文件中加载设置:

      # sysctl -p /etc/sysctl.d/10-netdev_budget.conf

验证

  • 监控 /proc/net/softnet_stat 文件中的第三列:

    # awk '{for (i=1; i<=NF; i++) printf strtonum("0x" $i) (i==NF?"\n":" ")}' /proc/net/softnet_stat | column -t

    如果值还在增加,请将 net.core.netdev_budget_usecsnet.core.netdev_budget 设置为更高的值。重复此过程,直到计数不再增加。