RSS(Receive Side Scaling)主要用来解决万兆及以上网卡在单队列模式下软中断集中在一个CPU核心的问题。网卡支持多队列后,收到数据包时可以根据报文头里的地址和端口信息计算哈希值,再依据哈希值的低位选择接收队列,让不同核心并行处理网络协议栈。这个过程中,哈希算法和间接表决定了流量如何分布,因此配置是否合理直接影响吞吐、延迟和CPU利用率。很多环境只开启了多队列,却没有检查RSS实际使用的哈希函数和密钥,导致队列负载严重不均衡。

先理解RSS哈希的计算对象和队列选择过程,才能知道修改哪些参数会改变分发结果。Linux、Windows以及部分智能网卡提供的配置入口有所差异,但底层逻辑是一致的。
RSS哈希算法的工作机制
RSS哈希通常采用Toeplitz哈希算法,这是微软在RSS规范中定义的标准算法,也被大多数Intel、Broadcom、Mellanox网卡硬件实现。它的输入是一组由网络报文头字段组成的元组:源IP地址、目的IP地址、源端口、目的端口,以及传输层协议类型。网卡硬件将这些字段按固定顺序排列,与一个称为哈希密钥的字节序列做逐位运算,最终得到一个32位哈希值。哈希值的低几位决定目标接收队列编号,例如有4个队列时取低2位,有8个队列时取低3位。由于同一条TCP流的元组固定,只要哈希密钥和间接表不变,数据包就始终进入同一个队列,从而避免同一连接的数据包乱序。
与简单异或哈希相比,Toeplitz哈希具有更好的分布特性。它的计算过程类似一个滑动窗口内积,对输入字段的位模式变化更敏感,硬件实现成本也较低,适合在网卡ASIC中完成线速处理。需要注意的是,哈希密钥的长度和内容都会影响分布结果。Linux下一些驱动默认使用全零或固定密钥,这在均匀流量下问题不大,但遇到高度聚集的源端口或IP段时,可能出现多个队列同时映射到同一个编号。此时仅增加队列数量无法改善负载,必须更换哈希密钥或调整间接表权重。
此外,RSS对非标准报文的处理往往不如预期。VXLAN、GRE、Geneve等隧道报文默认只使用外层头部做哈希,同一隧道内的大量内层流可能被分配到同一个队列;IPv6分片报文如果缺少端口信息,哈希输入会退化到IP地址对;某些网卡对IP分片或ARP报文直接交给默认队列0。理解这些限制后,就可以针对业务特征决定是否需要启用网卡的隧道RSS扩展,或者使用Flow Director等机制覆盖默认哈希行为。
Linux与Windows下的RSS配置命令
在Linux系统上,ethtool是管理网卡RSS最常用的工具。首先应查看网卡当前队列数量和RSS能力,使用ethtool -l eth0可以获取最大可配置的combined队列数,使用ethtool -x eth0可以看到当前哈希函数、间接表和哈希密钥。许多发行版默认没有开启全部队列,需要先设置队列数量,再配置RSS参数。下面是一个将网卡队列数调整为4并开启RSS的示例:
# 查看队列能力 ethtool -l eth0 # 设置收发合并队列数为4 ethtool -L eth0 combined 4 # 查看当前RSS配置 ethtool -x eth0
如果当前哈希函数是toeplitz但队列分布仍不均匀,可以尝试更换哈希密钥。密钥通过ethtool -X命令写入,格式为冒号分隔的十六进制字节,长度由驱动决定,常见为40字节或52字节。部分网卡还支持xor哈希,但异或哈希在对称流量下容易碰撞,除非硬件和驱动明确推荐,否则不建议在生产环境使用。配置完成后再次执行ethtool -x eth0,确认间接表条目是否按照预期分布到不同队列。
# 设置Toeplitz哈希和40字节测试密钥 ethtool -X eth0 hfunc toeplitz hkey 6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a:6d:5a # 为队列设置权重,权重比例决定间接表中各队列条目数量 ethtool -X eth0 weight 1 1 1 1
Windows Server和Windows客户端则通过PowerShell管理RSS。使用Get-NetAdapterRss可以查看网卡是否启用RSS、最大队列数以及当前的负载均衡Profile。使用Set-NetAdapterRss可以指定队列数、起始处理器和Profile类型。Windows的RSS同样基于Toeplitz哈希,但其间接表由系统根据Profile自动生成,通常不需要像Linux那样手动设置哈希密钥。常见的Profile包括Closest、NUMAStatic和Conservative,在虚拟化或NUMA架构下选择不同Profile会影响处理器亲和性和队列分布。
# 查看RSS状态 Get-NetAdapterRss -Name "Ethernet" # 设置RSS队列数为4,并指定NUMA静态负载均衡 Set-NetAdapterRss -Name "Ethernet" -NumberOfReceiveQueues 4 -Profile NUMAStatic
Windows下如果通过注册表调整RSS,需要修改网卡类GUID下的对应子键。例如在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001 中,可以找到*RSS或ReceiveSideScaling等值项。修改后必须重启网卡或系统才能生效,生产环境应优先使用PowerShell接口,减少误操作风险。
哈希密钥调优与队列分布验证
哈希密钥并不是越随机越好,但使用固定或全零密钥往往无法应对复杂流量。生产环境可以根据实际业务的五元组分布生成多个密钥,观察各队列收包数量和中软中断次数,选择分布最均匀的配置。Linux下可以先通过ethtool -S eth0查看每个队列的收包统计,再结合/proc/interrupts中的中断计数判断软中断是否分散到预期CPU核心。以下命令可以快速观察各队列收包是否均匀:
# 查看各队列收包计数 ethtool -S eth0 | grep -E 'rx_queue_[0-9]+_packets' # 观察中断变化 watch -d 'grep eth0 /proc/interrupts'
如果发现前几个队列计数远高于其他队列,可以先检查间接表是否配置为权重一致。ethtool -x eth0输出中的indirection table会列出每个表项对应的队列号,正常4队列下应大致循环出现0、1、2、3。若某队列出现频率明显过低,可以通过ethtool -X eth0 weight重新调整权重。需要注意的是,修改权重或哈希密钥后,只有新建立的流会按新规则分配,已有的TCP连接仍被网卡记录在流表或会话缓存中,因此验证时建议重启应用或等待连接自然老化。
对于隧道场景,部分智能网卡支持扩展RSS字段。例如Mellanox ConnectX系列可以通过固件参数或ethtool -U配置Flow Director,将内层IP和端口纳入哈希计算。Intel X710等网卡则提供ethtool -N设置RSS输入集。以Intel网卡为例,可以执行ethtool -N eth0 rx-flow-hash tcp4 sdfn和ethtool -N eth0 rx-flow-hash udp4 sdfn,其中sdfn表示源地址、目的地址、端口和协议都参与哈希。若驱动支持VXLAN,还可以通过类似命令将外层UDP端口排除,改用内层字段,以解决隧道流量集中单队列的问题。
验证RSS是否真正生效,不能只看网卡队列计数,还要确认中断亲和性。Linux下irqbalance服务可能动态迁移中断,与RSS的静态队列绑定冲突,建议在专用网络节点上关闭irqbalance,由管理员明确设置smp_affinity_list。例如将队列0绑定到CPU0,队列1绑定到CPU1,避免多个队列中断落在同一核心。结合mpstat -P ALL 1可以观察各核心的软中断CPU占用,如果仍然集中在某个核心,需要回头检查RSS间接表和哈希密钥是否合理。
常见配置误区与优化建议
实际配置中,一个典型误区是只增加网卡队列数,却没有同步增加RSS间接表的覆盖范围和中断绑定。即使网卡有16个队列,若间接表仍只映射到前4个队列,或者操作系统只为前4个队列分配中断向量,其他队列就是空转。因此调整队列数后必须确认驱动加载参数、RSS配置以及系统中断分配三者一致。Linux下可以使用lspci -vvv查看网卡MSI-X向量数量,Windows下可通过Get-NetAdapterAdvancedProperty检查Receive Buffers和RSS相关参数。
另一个容易被忽略的问题是虚拟化环境中的RSS行为。在VMware、Hyper-V或KVM虚拟机内部,虚拟网卡通常也支持RSS,但底层物理网卡和虚拟交换机可能已经做过一次哈希,导致双重哈希后队列分布反而不可控。此时应区分物理网卡的RSS和虚拟机内网卡的RSS,通常在宿主机上启用RSS并让虚拟交换机使用多队列即可,无需在虚拟机内部再次强制开启。对于容器环境,由于共享宿主机内核,RSS配置主要在物理网卡和宿主网络栈层面完成,容器内基本无需调整。
最后,建议将RSS配置纳入网络基线验证流程。每次调整哈希密钥、队列权重或中断绑定后,使用iperf3或netperf产生多流并发流量,检查各队列收包计数、CPU软中断分布和端到端吞吐。如果单流吞吐不受影响但多流吞吐下降,通常说明队列间负载不均衡或CPU缓存命中率降低。此时可以尝试恢复默认RSS参数,或在业务低峰期从队列数、间接表、哈希密钥三个维度逐步调整,直至找到适合当前流量的组合。