SMP 系统上具有多队列 NIC 的多线程

SMP 系统上具有多队列 NIC 的多线程

如何将数据包从网络接口队列调度到 CPU,然后再调度到线程进行处理?当涉及到如何跨队列对数据包进行哈希处理、硬件中断与软中断、CPU/内存/应用程序/线程局部性以及多线程与多进程守护进程时,需要考虑哪些因素,以尽可能避免数据包重新调度/复制?

我有一个多线程网络守护进程(例如,Unbound 解析器),在 Debian amd64 和 Linux 2.6.32(是的,旧版)上运行 16 个本机线程,因此应用程序负载分布在 16 个 CPU 上。网卡是 bnx2(BCM5709S),支持 8 个 MSI-X rx/tx 队列。通过在 /proc/irq/n/smp_affinity 中静态映射中断亲和性,将每个队列的 IRQ 分配给单独的 CPU(irqbalance 一直表现不佳),队列哈希类型(RSS 类型)是默认类型(IP src+dst、TCP sport+dport),使用默认哈希密钥。

所有这些都有助于分散负载,但并不均匀:通常有一个应用程序线程执行的工作量(=每秒请求数)是其他线程的两倍,而一个 CPU(可能是处理该特定线程的 CPU)的软中断率是其他 CPU 的两倍。

CPU 已启用超线程,但我还没有做任何事情来将负载分散到“真实”核心上(我确实应该这样做)。

Linux 带有相当全面的网络扩展文档,但我缺少一些空白:

文档中对 RSS 配置是这样描述的:

如果设备支持足够的队列,则典型的 RSS 配置是为每个 CPU 配备一个接收队列,否则每个内存域至少配备一个接收队列,其中内存域是一组共享特定内存级别(L1、L2、NUMA 节点等)的 CPU。

问:如何确定我的服务器的 CPU/缓存/内存域配置?

有关接收流控制(RFS)的信息似乎回答了我关于将数据包传送到正确的 CPU/线程的一些问题:

RFS 的目标是通过将数据包的内核处理引导至使用该数据包的应用程序线程正在运行的 CPU 来提高数据缓存命中率。

问:在 DNS 解析的情况下,通常有一个查询数据包和一个应答数据包。使用多线程守护进程,是否只有一个线程运行 bind()+recvfrom(),因此无论如何都必须处理所有新传入的数据包,然后再将工作安排到其他线程上?这种特定用例是否会从分叉操作(每个 CPU 一个进程)中受益?

问:接收流控制通常最适合于多线程 TCP 守护进程吗?

问:您如何确定是采用多线程还是多进程操作?显然存在共享内存和数据结构、资源争用等问题,但我考虑的是数据包流和应用程序侦听器。

问:如果没有接收流控制,或者只有简单的 UDP 服务,数据包是否会到达“错误”的 CPU,然后以某种方式重新调度到“正确”的 CPU?这会触发 NET_RX 软中断吗?

问:NIC 队列和 CPU 之间是否有 NET_RX 软中断?CPU 和监听线程/进程之间是否也有一个?如果接收线程将数据包调度到工作线程,是否还会有另一个软中断?如果这是可能的,那么是否还会有另一个?

遗憾的是,没有 Ben Hutchings 的视频或其他详细信息netconf 2011 演讲,他讲解了大部分内容。幻灯片比较简短。

我将尝试升级到具有可用性能版本的较新的内核,然后检查 CPU 的情况,也许能发现与其他 CPU 相比,负载更高的 CPU 的情况如何。

注意:我并不是想在这里解决某个特定问题,而是想了解这些东西在 Linux 内核中的工作原理。我还知道中断合并的各种选项。

相关内容