Red Hat Training

A Red Hat training course is available for RHEL 8

第 31 章 配置操作系统以优化对网络资源的访问

本节论述了如何配置操作系统以显示对工作负载中网络资源的优化访问。网络性能问题有时是硬件故障或基础架构故障造成的。解决这些问题超出了本文档的范围。

Tuned 服务提供了多个不同的配置集来提高多个特定用例的性能:

  • latency-performance
  • network-latency
  • network-throughput

31.1. 监控和诊断性能问题的工具

以下是 Red Hat Enterprise Linux 8 中可用的工具,用于监控系统性能并诊断与网络子系统相关的性能问题:

  • ss 实用程序打印有关套接字的统计信息,使管理员能够随着时间的推移评估设备性能。默认情况下,ss 显示已建立连接的开放非监听 TCP 套接字。利用命令行选项,管理员可以过滤掉有关特定套接字的统计信息。红帽建议使用 ss 替代 Red Hat Enterprise Linux 中已弃用的 netstat
  • ip 借助 实用程序,管理员可以管理和监控路由、设备、路由策略和隧道。ip 监控命令可以持续监控设备、地址和路由的状态。使用 -j 选项以 JSON 格式显示输出,该格式可进一步提供给其他实用程序以自动处理信息。
  • dropwatch 是一个交互式工具,由 dropwatch 软件包提供。它监控并记录内核丢弃的数据包。
  • ethtool 实用程序使管理员能够查看和编辑网络接口卡设置。使用此工具观察某些设备的统计信息,如该设备丢弃的数据包数量。使用 ethtool -S device name 命令,查看指定设备计数器的状态。
  • /proc/net/snmp 文件显示 snmp 代理用于 IP、ICMP、TCP 和 UDP 监控和管理的数据。定期检查此文件可帮助管理员识别异常值,从而识别潜在的性能问题。例如,在 /proc/net/snmp 文件中增加 UDP 输入错误(InErrors)可能表示套接字接收队列中存在瓶颈。
  • nstat 工具监控内核 SNMP 和网络接口统计信息.这个工具从 /proc/net/snmp 文件中读取数据,并以人类可读格式打印信息。
  • 默认情况下,由 systemtap-client 软件包提供的 SystemTap 脚本安装在 /usr/share/systemtap/examples/network 目录中:

    • nettop.stp: 脚本每 5 秒显示一个进程(进程标识符和命令)列表,其中包含发送和接收的数据包数,以及进程在该间隔期间发送和接收的数据量。
    • socket-trace.stp: 划分 Linux 内核的 net/socket.c 文件中的每个功能,并显示 trace 数据。
    • dropwatch.stp:每 5 秒,脚本会显示释放在内核中位置的套接字缓冲区数量。使用 --all-modules 选项查看符号名称。
    • latencytap.stp:此脚本记录了不同类型的延迟对一个或多个进程的影响。它每 30 秒打印延迟类型列表,按进程或进程等待的总时间降序排列。这可用于识别存储和网络延迟的原因。

    红帽建议在该脚本中使用 --all-modules 选项来更好地映射延迟事件。默认情况下,该脚本安装在 /usr/share/systemtap/examples/profiling 目录中。

  • BPF Compiler Collection(BCC)是一个库,它有助于创建扩展的 Berkeley Packet Filter(eBPF)程序。eBPF 程序的主要工具是分析操作系统性能和网络性能,而不会出现开销或安全问题。

其它资源

31.2. 数据包接收中的瓶颈

虽然网络堆栈在很大程度上是自我优化的,但网络数据包处理期间存在多个点,它们可能会成为瓶颈并降低性能。

以下是可能导致瓶颈的问题:

The buffer or ring buffer of the network card
如果内核丢弃大量数据包,硬件缓冲区可能会成为瓶颈。使用 ethtool 工具监控丢弃的数据包的系统。
The hardware or software interrupt queues
中断可能会增加延迟和处理器争用。有关处理器如何处理中断的详情,请参阅中断请求概述、手动 Balancing 中断和 设置 smp_affinity 掩码
The socket receive queue of the application
许多未复制的数据包或者 /proc/net/snmp 文件中的 UDP 输入错误(InErrors)增加,表示应用程序的接收队列存在瓶颈。

如果硬件缓冲丢弃了大量数据包,则以下是一些可能的解决方案:

Slow the input traffic
过滤传入流量,减少加入的多播组数量,或者减少广播流量以降低队列填充的速度。
Resize the hardware buffer queue

调整硬件缓冲区队列的大小:通过增大队列的大小来减少丢弃的数据包数量,使其不会像容易那样轻松地溢出。您可以使用 ethtool 命令修改网络设备的 rx/tx 参数:

ethtool --set-ring device-name value

Change the drain rate of the queue
  • 通过在到达队列前过滤或丢弃数据包,或通过降低设备的权重来降低队列填充的速度。过滤传入流量或降低网络接口卡的设备权重,以减慢传入的流量速度。

    设备权重指的是设备在单个调度处理器访问中一次可接收的数据包数量。您可以通过增加由 dev_weight 内核设置控制的设备权重来提高队列排空的速率。要临时更改此参数,请更改 /proc/sys/net/core/dev_weight 文件的内容,或者永久更改,使用 procps-ng 软件包提供的 sysctl 命令。

  • 增加应用的套接字队列的长度:这通常是提高套接字队列排空率的最简单方法,但不太可能是长期解决方案。如果套接字队列接收的突发流量有限,增加套接字队列的深度以匹配突发流量的大小可能会阻止数据包被丢弃。要增大队列的深度,请通过以下更改之一增加套接字接收缓冲的大小:

    • 增加 /proc/sys/net/core/rmem_default 参数的值:此参数控制套接字使用的接收缓冲的默认大小。这个值必须小于或等于 proc/sys/net/core/rmem_max 参数的值。
    • 使用 setsockopt 配置更大的 SO_RCVBUF 值: 这个参数控制套接字接收缓冲的最大字节大小。使用 getsockopt 系统调用来确定缓冲区的当前值。

更改队列的排空率通常是降低网络性能的最简单方法。但是,增加设备一次接收的数据包数量会使用额外的处理器时间,在此期间无法调度其他进程,因此可能会导致其他性能问题。

其它资源

  • ss(8)socket(7)ethtool(8) man page
  • /proc/net/snmp file

31.3. 忙碌轮询

如果分析揭示了高延迟,则您的系统可能会从基于轮询的数据包接收中受益,而非基于中断的数据包接收。

繁忙的轮询有助于减少网络接收路径的延迟,允许套接字层代码轮询网络设备的接收队列,并禁用网络中断。这删除了中断和结果上下文切换造成的延迟。不过,它也会增加 CPU 利用率。忙碌轮询也会阻止 CPU 休眠,这可能会产生额外的功耗。所有设备驱动程序都支持忙碌轮询行为。

其它资源

31.3.1. 启用忙碌轮询

默认情况下,禁用忙碌轮询。这个步骤描述了如何启用繁忙的轮询。

流程

  1. 确定启用了 CONFIG_NET_RX_BUSY_POLL 编译选项:

    # cat /boot/config-$(uname -r) | grep CONFIG_NET_RX_BUSY_POLL
    CONFIG_NET_RX_BUSY_POLL=y
  2. 启用忙碌轮询

    1. 要在特定套接字上启用忙碌轮询,请将 sysctl.net.core.busy_poll 内核值设置为 0 以外的值:

      # echo "net.core.busy_poll=50" > /etc/sysctl.d/95-enable-busy-polling-for-sockets.conf
      # sysctl -p /etc/sysctl.d/95-enable-busy-polling-for-sockets.conf

      这个参数控制在套接字轮询中等待数据包的微秒数并选择 syscalls。红帽建议使用 50 值。

    2. 在套接字中添加 SO_BUSY_POLL 套接字选项。
    3. 要在全局范围内启用忙碌轮询,请将 sysctl.net.core.busy_read 设置为 0 以外的值:

      # echo "net.core.busy_read=50" > /etc/sysctl.d/95-enable-busy-polling-globally.conf
      # sysctl -p /etc/sysctl.d/95-enable-busy-polling-globally.conf

      net.core.busy_read 参数控制在设备队列中等待套接字读取数据包的微秒数。它还设置 SO_BUSY_POLL 选项的默认值。红帽建议为少量套接字使用 50 值,对于大量套接字,值为 100。对于非常大的插槽,例如超过数百个,使用 epoll 系统调用。

验证步骤

  • 验证是否启用了忙碌轮询

    # ethtool -k device | grep "busy-poll"
    busy-poll: on [fixed]
    
    # cat /proc/sys/net/core/busy_read
    50

其它资源

31.4. 接收扩展

接收扩展(RSS)(也称为多队列接收)可在多个基于硬件的接收队列之间分发网络接收处理,允许多个 CPU 处理入站网络流量。RSS 可用于减轻因单个 CPU 过载导致的接收中断处理方面的瓶颈,并降低网络延迟。默认情况下启用 RSS。

在适当的网络设备驱动程序中配置应处理 RSS 网络活动的队列数量或 CPU 数量:

  • 对于 bnx2x 驱动程序,它在 num_queues 参数中配置。
  • 对于 sfc 驱动程序,它在 rss_cpus 参数中配置。

不管如何,它通常在 /sys/class/net/device/queues/rx-queue/ 目录中配置,其中 device 是网络设备的名称(如 enp1s0)和rx-queue 是相应接收队列的名称。

irqbalance 守护进程可与 RSS 结合使用,以减少跨节点内存传输和缓存行重新使用的可能性。这降低了处理网络数据包的延迟。

31.4.1. 查看中断请求队列

在配置接收扩展(RSS)时,红帽建议将队列数量限制为每个物理 CPU 内核一个队列。超线程通常在分析工具中作为单独的核心来表示,但为所有核心(如超线程)配置队列并不对网络性能有用。

启用后,RSS 根据每个 CPU 的处理量在可用 CPU 之间均匀分配网络处理。但是,使用 ethtool 工具的 --show-rxfh-indir--set-rxfh-indir 参数,修改 RHEL 分发网络活动的方式,并平衡某些类型的网络活动的重要性。

这个步骤描述了如何查看中断请求队列。

流程

  • 要确定您的网络接口卡是否支持 RSS,检查多个中断请求队列是否与 /proc/interrupts 中的接口关联:

    # egrep 'CPU|p1p1' /proc/interrupts
     CPU0    CPU1    CPU2    CPU3    CPU4    CPU5
    89:   40187       0       0       0       0       0   IR-PCI-MSI-edge   p1p1-0
    90:       0     790       0       0       0       0   IR-PCI-MSI-edge   p1p1-1
    91:       0       0     959       0       0       0   IR-PCI-MSI-edge   p1p1-2
    92:       0       0       0    3310       0       0   IR-PCI-MSI-edge   p1p1-3
    93:       0       0       0       0     622       0   IR-PCI-MSI-edge   p1p1-4
    94:       0       0       0       0       0    2475   IR-PCI-MSI-edge   p1p1-5

    输出显示 NIC 驱动程序为 p1p1 接口(p1p1-0p1p1-5)创建了 6 个接收队列。它还显示每个队列处理了多少个中断,以及服务中断的 CPU。在这种情况下,有 6 个队列,因为默认情况下,这个特定 NIC 驱动程序会为每个 CPU 创建一个队列,此系统具有 6 个 CPU。在 NIC 驱动程序中,这是相当常见的模式。

  • 使用地址 0000:01:00.0 列出 PCI 设备的中断请求队列:

    # ls -1 /sys/devices/*/*/0000:01:00.0/msi_irqs
    101
    102
    103
    104
    105
    106
    107
    108
    109

31.5. 接收数据包表

接收数据包声明(RPS)与接收侧边扩展(RSS)类似,因为它用于将数据包定向到特定 CPU 进行处理。但是,RPS 在软件级别上实施,有助于防止单个网络接口卡的硬件队列成为网络流量的瓶颈。

与基于硬件的 RSS 相比,RPS 具有几个优点:

  • RPS 可以和任何网络接口卡一起使用。
  • 可以在 RPS 中添加软件过滤器,以处理新协议。
  • RPS 不会增加网络设备的硬件中断率。然而,它确实引入了处理器间中断。

RPS 根据网络设备和接收队列配置,在 /sys/class/net/device/queues/rx-queue/rps_cpus 文件中,其中 device 是网络设备的名称,如 enp1s0 andrx-queue 是相应接收队列的名称,如 rx-0。

rps_cpus 文件的默认值为 0。这会禁用 RPS,CPU 处理网络中断并处理数据包。要启用 RPS,使用应处理指定网络设备数据包并接收队列的 CPU 配置适当的 rps_cpus 文件。

rps_cpus 文件使用以逗号分隔的 CPU 位映射。因此,要允许 CPU 处理接口上接收队列的中断,请将它们在位图中的位置值设置为 1。例如,若要使用 CPU 0123 处理中断,可将 rps_cpus 的值设置为 f,这是 15 的十六进制值。在二进制表示中,1500001111 (1+2+4+8)

对于具有单传输队列的网络设备,可以通过将 RPS 配置为使用同一内存域中的 CPU 来实现最佳性能。在非 NUMA 系统上,这意味着可以使用所有可用的 CPU。如果网络中断率非常高,除处理网络中断的 CPU 外,也可以提高性能。

对于有多个队列的网络设备,配置 RPS 和 RSS 时通常没有好处,因为 RSS 被配置为默认将 CPU 映射到每个接收队列。但是,如果硬件队列比 CPU 少,并且 RPS 配置为在同一内存域中使用 CPU,则 RPS 仍然很有用。

31.6. 接收流畅

接收流速(RFS)扩展接收数据包定位(RPS)行为,以提高 CPU 缓存命中率,从而减少网络延迟。当 RPS 仅根据队列长度转发数据包时,RFS 使用 RPS 后端来计算最合适的 CPU,然后根据使用数据包的应用程序的位置转发数据包。这提高了 CPU 缓存效率。

从单个发送器接收的数据不会发送到多个 CPU。如果单个发送方收到的数据量大于单个 CPU 可处理的数据量,请配置更大的帧大小以减少中断数量,从而减少 CPU 处理工作的数量。或者,考虑 NIC 卸载选项或更快的 CPU。

考虑将 numactltaskset 与 RFS 结合使用,将应用程序固定到特定的内核、套接字或 NUMA 节点。这有助于防止数据包被不按顺序处理。

31.6.1. 启用接收流(接收流)

默认情况下禁用接收流(RFS)。这个步骤描述了如何启用 RFS。

流程

  1. net.core.rps_sock_flow_entries 内核值的值设置为预期的并发活跃连接的最大数量:

    # echo "net.core.rps_sock_flow_entries=32768" > /etc/sysctl.d/95-enable-rps.conf
    注意

    红帽建议为中等服务器负载使用 32768 值。输入的所有值在实际中都被舍入到 2 最接近的容量。

  2. 永久设置 net.core.rps_sock_flow_entries

    # sysctl -p /etc/sysctl.d/95-enable-rps.conf
  3. sys/class/net/device/queues/rx-queue/rps_flow_cnt 文件的值临时设置为(rps_sock_flow_entries/N)的值,其中 N 是设备中的接收队列数:

    # echo 2048 > /sys/class/net/device/queues/rx-queue/rps_flow_cnt

    使用您要配置的网络设备的名称替换 device(例如,enp1s0),并将rx-queue 替换为您要配置的接收队列(例如:rx-0)。

    使用配置的接收队列数量替换 N。例如,如果 rps_flow_entries 被设置为 32768,并且有 16 配置的接收队列,则 rps_flow_cnt = 32786/16= 2048 (即 rps_flow_cnt = rps_flow_enties/N )。

    对于单队列设备,rps_flow_cnt 的值与 rps_sock_flow_entries 值相同。

  4. 在所有网络设备中永久启用 RFS,创建 /etc/udev/rules.d/99-persistent-net.rules 文件并添加以下内容:

    SUBSYSTEM=="net", ACTION=="add", RUN{program}+="/bin/bash -c 'for x in /sys/$DEVPATH/queues/rx-*; do echo 2048 > $x/rps_flow_cnt;  done'"
  5. 可选:在特定网络设备中启用 RPS:

    SUBSYSTEM=="net", ACTION=="move", NAME="device name" RUN{program}+="/bin/bash -c 'for x in /sys/$DEVPATH/queues/rx-*; do echo 2048 > $x/rps_flow_cnt; done'"

    使用实际网络设备名称替换设备名称

验证步骤

  • 验证是否启用了 RFS:

    # cat /proc/sys/net/core/rps_sock_flow_entries
    32768
    
    # cat /sys/class/net/device/queues/rx-queue/rps_flow_cnt
    2048

其它资源

  • sysctl(8) man page

31.7. 加速的 RFS

通过添加硬件辅助功能,加速 RFS 提升了接收流(RFS)的速度。与 RFS 一样,数据包根据使用数据包的应用程序的位置进行转发。

但是,与传统的 RFS 不同,数据包直接发送到使用数据的线程的本地 CPU:

  • 执行应用的 CPU
  • 或者缓存层次结构中该 CPU 本地的 CPU

只有满足以下条件时,加速的 RFS 才可用:

  • NIC 必须支持加速的 RFS。导出 ndo_rx_flow_steer() 功能的卡支持加速 RFS。net_device检查 NIC 的数据表,以确保是否支持此功能。
  • ntuple 必须启用过滤。有关如何启用这些过滤器的详情,请参考 启用 ntuple 过滤器

满足这些条件后,根据传统的 RFS 配置自动停用 CPU 到队列映射。也就是说,CPU 到队列映射将根据驱动程序为每个接收队列配置的 IRQ 影响而降低。有关启用传统 RFS 的更多信息,请参阅启用接收流域

31.7.1. 启用 ntuple 过滤器

必须启用 ntuple 过滤。使用 ethtool -k 命令启用 ntuple 过滤器。

流程

  1. 显示 ntuple 过滤器的当前状态:

    # ethtool -k enp1s0 | grep ntuple-filters
    
    ntuple-filters: off
  2. 启用 ntuple 过滤器:

    # ethtool -k enp1s0 ntuple on
注意

如果输出是 ntuple-filters: off [fixed],则禁用 ntuple 过滤,且您无法配置它:

# ethtool -k enp1s0 | grep ntuple-filters
ntuple-filters: off [fixed]

验证步骤

  • 如果启用了 ntuple 过滤器:

    # ethtool -k enp1s0 | grep ntuple-filters
    ntuple-filters: on

其它资源

  • ethtool(8) man page