网络栈调优98 条

RPS/RFS 软件收包分发

单队列网卡或中断集中导致单核软中断打满时, 可用 RPS 把收包处理分散到多核, 再用 RFS 让同一条流固定到应用所在核。

RPS 与 RFS 是什么

RPS(Receive Packet Steering)用软件方式把收包处理分散到多个 CPU,适用于单队列网卡与虚拟网卡;RFS(Receive Flow Steering)在其之上记录流与 CPU 的对应关系,让处理同一条流的应用线程与收包处理尽量落在同一核上,减少跨核缓存失效。二者都作用于收包路径,是缺少硬件多队列时的补强手段。

基本信息

rps_cpus每个接收队列的 CPU 位图,十六进制表示
rps_flow_cnt该队列的流表条目数
rps_sock_flow_entries全局 socket 流表条目数,位于 /proc/sys/net/core/
配置路径/sys/class/net/<dev>/queues/rx-*/
适用前提单队列网卡或虚拟网卡,软中断集中在少数核上

典型使用场景

  • 虚拟网卡只有单队列,软中断把单个 CPU 打满
  • 容器网络收包集中在少数核,业务线程排队等 CPU
  • 测试环境网卡不支持多队列,却要模拟高并发收包
  • 与中断亲和配合,把收包与业务线程放在同一 NUMA 节点
  • CPU 拓扑不均衡时手工引导流量,避免个别核长期饱和

启用 RPS

启用 RPS
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries      # 全局流表条目
echo ffff > /sys/class/net/eth0/queues/rx-0/rps_cpus        # 启用 CPU0-15
echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt   # 该队列的流表条目
cat /proc/softirqs | head -5                                # 观察软中断分布是否变均衡

参数作用

参数作用注意
rps_cpus指定哪些 CPU 参与该队列的收包处理十六进制位图,写错会集中到单核
rps_flow_cnt每队列可跟踪的流数量过小会导致回退到无流信息的分发
rps_sock_flow_entries全局流表规模需大于各队列 rps_flow_cnt 之和
rps_cpus 是十六进制位图:1 表示仅 CPU0,4 表示仅 CPU2,ffff 表示 CPU0 到 CPU15。写错掩码会让流量集中到一个核,效果与调优目标相反。
RFS 的收益依赖流表:只开 RPS 而不配置 rps_sock_flow_entries 与 rps_flow_cnt,收包会在核间迁移并带来额外的缓存失效开销。

验证与回退

  • 启用后对比 /proc/softirqs 中各 CPU 的 NET_RX 增量是否趋于均衡
  • 压测对比启用前后的收包吞吐与 CPU 使用率,确认收益确实存在
  • 收益不明显或延迟变差时,把 0 写回 rps_cpus 即可关闭
  • 关闭后确认软中断分布回到原状,避免只改了部分队列
  • 配置需写入开机脚本或 udev 规则,否则重启后失效

易错点

  • 把 rps_cpus 写成十进制或写错位图,导致流量集中到单核
  • 网卡已有硬件 RSS 多队列仍叠加 RPS,只增加一次软件分发开销
  • 只配队列的 rps_flow_cnt 而忘记全局 rps_sock_flow_entries,RFS 实际不生效
  • 把 RPS 当作降低延迟的手段,它主要提升收包吞吐,反而可能略微增加延迟

数据来源与参考

  • Linux Documentation/networking/scaling.rst
  • Linux Documentation/admin-guide/sysctl/net.rst
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌