服务器网卡多队列与中断绑定入门:RPS、RSS 与 irqbalance 怎么取舍

    发布时间:2026-09-20 12:30 更新时间:2026-09-20 12:30 阅读量:0

    很多站长遇到过高流量时的怪现象:CPU 总体占用并不高,但网卡收包速率上不去,top 里 si(软中断)这一项却一直飘红,或者只有一个核被 ksoftirqd 吃满。这类问题往往不是带宽不够,而是收包路径上只有一颗 CPU 在干活。本文从原理讲到命令,帮你理清 RSS、RPS 和 irqbalance 三者的关系,知道什么场景该调、什么场景保持默认更稳。

    先搞清楚:网卡队列、RSS 与中断是怎么配合的

    现代服务器网卡普遍支持多队列(multi-queue)。一块物理网卡在系统里会呈现为 eth0 以及若干 eth0-0、eth0-1 这样的队列接口,每个队列对应一组独立的收发描述符。当数据包到达时,网卡根据包头的四元组做哈希,把同一个连接的数据尽量分到同一个队列,这个过程叫 RSS(Receive Side Scaling)。哈希结果由网卡硬件决定,好处是同一连接不乱序,代价是队列之间负载不一定均匀。

    每个队列会向某个 CPU 发送中断,通知内核来取包。如果某块网卡的所有队列中断都落在 CPU0,那就等于回到了单核收包。所以多队列要真正生效,需要两件事同时成立:队列数量足够,且中断被分散到不同 CPU 上。

    如果网卡硬件或虚拟化环境不支持多队列(不少云主机、老网卡就是单队列),内核还提供了软件层的 RPS(Receive Packet Steering)。RPS 在软中断阶段根据哈希把包重新分发给其他 CPU 的 backlog 队列,相当于软件模拟 RSS。配套的 RFS 则尝试把包交给运行该 socket 的 CPU,减少跨核缓存失效。RPS 会额外消耗 CPU 做分发,所以它是硬件能力不足时的补救手段,不是无代价的优化。

    动手查看:队列数、中断分布与 RPS 开关

    排查前先确认网卡和驱动支持多少队列。下面的命令都是只读查询,不会改动线上配置,具体输出字段以你的内核与驱动版本为准。

    # 查看网卡队列与中断信息,不同驱动输出字段略有差异
    ethtool -l eth0
    
    

    查看网卡各队列的中断号

    ls /sys/class/net/eth0/queues/

    统计每个中断号在各 CPU 上的触发次数,观察是否集中在某一核

    cat /proc/interrupts | grep -i eth0

    查看某队列的 RPS 配置(为空表示未启用)

    cat /sys/class/net/eth0/queues/rx-0/rps_cpus

    查看 RFS 流表大小

    cat /proc/sys/net/core/rps_sock_flow_entries

    看 /proc/interrupts 时重点关注两件事:一是网卡占用了几个中断号,二是每行后面的数字是否明显偏向某一列(某一颗 CPU)。如果所有中断都堆在 CPU0,同时 si 很高,基本可以确认是中断集中导致。

    需要临时验证 RPS 效果时,可以这样写掩码(十六进制,每个 bit 对应一颗 CPU,f 表示 CPU0~3):

    # 让 rx-0 队列的软中断在 CPU0-3 上分担
     echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus
    
    

    适当设置 RFS 流表条目,0 表示关闭

    sysctl -w net.core.rps_sock_flow_entries=32768

    该队列对应的 RFS 流表大小

    sysctl -w net.core.rps_sock_flow_entries=32768

    每个 rx 队列可用的流表条目写在队列目录下

    echo 4096 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt

    这些 /sys 下的写入重启即失效,想持久化需写进 systemd 服务、udev 规则或网卡调优脚本,不同发行版做法不一,以官方文档为准。注意 RPS 掩码不要跨 NUMA 节点随意扩散,否则包在节点间来回搬运反而更慢。

    irqbalance 与手动绑定:什么时候该接管

    irqbalance 是多数发行版默认开启的中断均衡服务,它会周期性把中断迁移到相对空闲的 CPU 上。对通用业务来说,默认开启通常够用,不建议上来就关。但在下面这些场景,手动绑定往往更稳定:

    一是网卡支持 RSS 且队列数与业务核数匹配,希望中断固定落在特定物理核上,避免迁移带来的缓存抖动;二是做了 CPU 隔离(isolcpus、cgroup cpuset)把业务进程钉在指定核,需要把网卡中断也钉到对应的核;三是延迟敏感型服务,抖动比吞吐更重要。

    手动绑定用 /proc/irq/<中断号>/smp_affinity_list 或 smp_affinity(十六进制掩码)。下面的例子把中断 128 绑到 CPU2:

    # 查看该中断当前绑定的 CPU
    cat /proc/irq/128/smp_affinity_list
    
    

    绑定到 CPU2(列表形式,支持 2 或 2-3 这样的范围)

    echo 2 > /proc/irq/128/smp_affinity_list

    如使用十六进制掩码,CPU2 对应 4

    echo 4 > /proc/irq/128/smp_affinity

    停用 irqbalance 前先确认它是否在运行

    systemctl status irqbalance

    如果你决定手动绑定,建议先 systemctl stop irqbalance 并 disable,否则它会把你的设置改回去。做这一步前务必留好回滚方式:记录原始 smp_affinity_list 值,或准备好重新启用 irqbalance 的命令。生产环境建议先在测试机验证,再灰度上线。

    取舍上可以记一个简单原则:能靠硬件 RSS 解决就别用 RPS,能靠默认 irqbalance 稳住就别手动绑。只有当监控明确显示中断集中、si 偏高、单核软中断饱和,且业务对延迟或吞吐有进一步要求时,才值得进入手动调优。调整后继续用 /proc/interrupts 和 mpstat -P ALL 1 观察分布是否改善,而不是凭感觉认为“绑了就更快”。

    小结与下一步

    收包性能问题先看队列数和中断分布,再判断是硬件多队列没生效、队列数不够,还是中断全挤在一颗核上。RSS 是硬件分流,RPS 是软件补救,irqbalance 负责动态均衡,三者不是互相替代而是配合关系。建议你先用 ethtool -l、/proc/interrupts 和 mpstat 建立一份基线数据,确认瓶颈确实在收包路径,再考虑关闭 irqbalance 做手动绑定。任何改动都保留回滚脚本,并关注业务指标而非单一系统指标。

    继续阅读

    📑 📅
    Linux时间与时区排查:date、timedatectl与容器时区一致性 2026-09-20
    Docker 容器日志写满磁盘:json-file 限制与 max-size 配置 2026-09-20
    Nginx 与后端长连接调优:keepalive 与 upstream 复用 2026-09-20
    Docker 容器内 CPU 被限流排查:cfs_quota、cpuset 与 top 显示异常 2026-09-19
    Nginx gzip 与 Brotli 压缩配置实战:静态资源体积优化 2026-09-19
    Nginx 上传大文件报 413 与超时:参数与缓冲区排查 2026-09-20
    Docker容器缺命令:精简镜像补装与临时容器调试 2026-09-20
    Nginx location 匹配优先级实战:=、^~、~ 命中顺序验证 2026-09-21
    Docker 容器健康检查实战:HEALTHCHECK 与 unhealthy 自动重启 2026-09-21
    MySQL索引失效排查:EXPLAIN执行计划与隐式转换定位 2026-09-21