4. 多队列技术原理:RSS(Receive Side Scaling)核心概念
随着网络带宽从 1Gbps 向 10Gbps、25Gbps 乃至 100Gbps 演进,单核 CPU 已无法独立完成线速收包处理。RSS(Receive Side Scaling,接收端缩放)是网卡多队列技术的基石,它允许网卡将入站数据流分散到多个硬件接收队列,进而分发至不同 CPU 核心并行处理,从根本上消除单核瓶颈。
4.1 RSS 解决的问题:单队列瓶颈
在传统单队列 NIC 模型中,所有入站数据包共享一个接收描述符环(RX Ring),由单个 CPU 核心负责中断处理与协议栈上送。该模型存在三个致命缺陷:
- 中断风暴:高吞吐下单个 CPU 被中断淹没,无法调度用户态进程。
- 缓存抖动:单核 L1/L2 缓存无法容纳海量连接上下文,频繁 cache miss。
- 锁竞争:协议栈全局锁(如 sock_alloc)在单核上无意义,但多核场景下若仍由单核处理,则成为伪共享瓶颈。
性能指标对比: 在 10Gbps 线速下,单队列方案收包吞吐通常不超过 2.5 Mpps(百万包/秒),而启用 RSS 多队列后,8 队列可线性扩展至 18–20 Mpps,CPU 利用率从单核 100% 降为每核 12–15%。
4.2 RSS 核心机制:哈希分发
RSS 的核心是一个可编程的 Toeplitz 哈希引擎,位于网卡 MAC 层与 DMA 引擎之间。每个入站数据包经过哈希计算后,其结果用于索引一个重定向表(Indirection Table),从而决定该包进入哪个接收队列。
关键点: RSS 哈希是确定性的——同一五元组(源IP、目的IP、源端口、目的端口、协议)始终映射到同一队列,保证 TCP 流的有序性;不同流则均匀散列到不同队列,实现并行。
4.2.1 哈希输入元组
| 协议类型 | 哈希输入字段 | 典型哈希键长度 |
|---|---|---|
| IPv4 TCP/UDP | 源IP + 目的IP + 源端口 + 目的端口 | 40 字节(4+4+2+2) |
| IPv4 仅IP | 源IP + 目的IP | 8 字节 |
| IPv6 TCP/UDP | 源IP(128bit) + 目的IP(128bit) + 端口 | 36 字节 |
| IPv4/IPv6 隧道 | 内层 IP 头字段(需网卡支持) | 可变 |
4.2.2 重定向表与队列映射
哈希值(通常为 32 位)并不直接对应队列编号,而是通过一个 间接表(Indirection Table,IT) 进行映射。IT 的大小通常为 128 或 512 项,每项存储一个队列 ID(0 ~ N-1)。
// 伪代码:RSS 队列选择流程
uint32_t hash = toeplitz_hash(packet_header, rss_key);
uint32_t index = hash & (indirection_table_size - 1);
uint16_t queue_id = indirection_table[index];
// 将 packet DMA 到 queue_id 对应的 RX Ring
注意: 间接表大小必须是 2 的幂,且与硬件队列数无关。例如 128 项的 IT 可映射到 16 个队列,每 8 个连续槽位指向同一队列,实现加权分发。
4.3 RSS 硬件架构与数据流
下图展示了 RSS 在网卡内部的完整处理流水线:
4.4 RSS 关键参数与配置
Linux 下通过 ethtool 工具可完整查看和调整 RSS 参数:
# 查看网卡 RSS 队列数
ethtool -l eth0
# 输出示例:
# Combined: 8
# RX: 8
# TX: 8
# 设置 RSS 队列数为 8
ethtool -L eth0 combined 8
# 查看当前 RSS 哈希配置
ethtool -x eth0
# 输出示例:
# RSS hash function: toeplitz
# RSS hash key: 6d:5a:56:da:25:5b:0e:c2:41:67:25:3d:43:a3:8f:b0:...
# RSS indirection table: 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 ...
# 自定义 RSS 哈希键(40 字节十六进制)
ethtool -X eth0 hkey 6d:5a:56:da:25:5b:0e:c2:41:67:25:3d:43:a3:8f:b0:...
# 设置 RSS 哈希输入元组(仅 IPv4 TCP)
ethtool -N eth0 rx-flow-hash tcp4 sdfn
4.4.1 哈希输入元组标志
| 标志 | 含义 | 典型使用场景 |
|---|---|---|
s |
源 IP 地址 | 基础负载均衡 |
d |
目的 IP 地址 | 基础负载均衡 |
f |
IP 协议号(如 TCP=6, UDP=17) | 区分协议类型 |
n |
源端口 | 细粒度流分发 |
r |
目的端口 | 细粒度流分发 |
4.5 RSS 与 CPU 亲和性的联动
RSS 仅保证数据包被分发到不同硬件队列,但队列的中断处理程序最终运行在哪个 CPU 核心上,由 中断亲和性(IRQ Affinity) 决定。两者必须联动配置才能实现真正的负载均衡:
- RSS 层:通过哈希将流散列到不同队列,避免单队列拥塞。
- IRQ Affinity 层:将每个队列的中断绑定到指定 CPU 核心,确保中断处理与后续协议栈处理在同一核心上完成,最大化缓存局部性。
最佳实践: 在 16 核服务器上,若网卡支持 8 个 RSS 队列,应将队列 0–7 的中断分别绑定到 CPU 0–7,并确保 CPU 0–7 上的其他非必要中断(如存储、时钟)被迁移到 CPU 8–15,避免干扰。
4.6 RSS 的局限性
- 哈希冲突:不同流可能映射到同一队列,导致局部热点。可通过增大间接表或使用对称哈希缓解。
- 不支持 UDP 多流:UDP 无连接概念,部分网卡默认仅对 IP 对做哈希,导致所有 UDP 流量进入同一队列。
- 虚拟化环境:在 SR-IOV VF 中,RSS 功能取决于物理网卡和 PF 驱动支持,部分 VF 仅支持单队列。
- 无法感知应用负载:RSS 是纯硬件哈希,无法根据 CPU 当前利用率动态调整分发策略。
排查提示: 若发现某个 CPU 核心的软中断(si)利用率持续高于其他核心,使用
cat /proc/interrupts | grep eth0 检查各队列中断分布,再通过 ethtool -x eth0 验证间接表是否均匀映射。