在CentOS服务器上,当网卡流量超过单核处理能力时,软中断(softirq)会集中在一个CPU核心上打满,导致丢包、延迟飙升。解决这个问题的核心手段就是通过sysctl参数调优网卡队列,再配合RPS(Receive Packet Steering)和RFS(Receive Flow Steering)把网络包分发到多个CPU核心上处理。具体做法是:先用ethtool把网卡的多队列打开,设置队列数等于CPU核心数,然后通过sysctl开启rps和rfs,最后把每个网卡队列的中断亲和性绑定到不同CPU上。这套组合拳打下来,单网卡吞吐量可以轻松翻倍,PPS处理能力提升数倍。
一、先搞清楚软中断为什么会成为瓶颈
Linux内核处理网络包的流程是这样的:网卡收到数据包后触发硬件中断,内核在中断处理程序里把数据放到网卡的接收队列里,然后触发软中断(NET_RX_SOFTIRQ)来真正处理这些数据包。问题在于,默认情况下,一个网卡只有一个接收队列,所有数据包的软中断都在同一个CPU核心上处理。当流量达到几十万PPS或者几Gbps带宽时,单核根本扛不住,CPU使用率直接100%,数据包来不及处理就被丢弃了。
二、查看当前网卡中断和软中断分布情况
动手调优之前,先看现状。用下面几条命令快速诊断:
# 查看每个CPU核心的软中断分布 cat /proc/softirqs | grep NET_RX # 查看网卡中断绑定到了哪个CPU cat /proc/interrupts | grep eth # 查看网卡支持几个队列 ethtool -l eth0 # 查看当前网卡队列数和中断数 ethtool -c eth0
如果你看到NET_RX那一行的数字大部分集中在cpu0或者某一个核心上,而且ethtool -l显示队列数只有1,那就是典型的单队列瓶颈。如果你用的是多队列网卡(比如Intel的ixgbe、i40e、ixgbevf等),那恭喜你,硬件基础已经具备了,只需要做软件配置。
三、用ethtool开启网卡多队列
这是第一步,也是最关键的一步。没有多队列,后面的RPS和RFS都是空谈。假设你的网卡是eth0,CPU有8个核心,操作如下:
# 查看网卡支持的最大队列数 ethtool -l eth0 # 设置队列数为8(等于CPU核心数) ethtool -L eth0 combined 8 # 确认设置成功 ethtool -c eth0
注意,combined参数表示收发共用队列数。有些网卡支持分开设置收发队列,用tx和rx参数分别指定。设置完之后,你会发现/proc/interrupts里eth0的中断变成了eth0-0、eth0-1、eth0-2……每个队列对应一个中断。这一步只是把硬件队列打开了,但默认情况下这些中断可能还是集中在一个CPU上,所以还需要下一步。
四、配置中断亲和性(IRQ Affinity)
中断亲和性的作用是把每个网卡队列的硬件中断绑定到指定的CPU核心上。CentOS 7/8系统里,中断亲和性文件在/proc/irq/目录下。先找到每个队列对应的中断号:
# 查看eth0各队列的中断号 cat /proc/interrupts | grep eth0
假设输出显示eth0-0对应中断号120,eth0-1对应121,以此类推。然后把每个中断绑定到对应的CPU:
# 把中断120绑定到CPU0 echo 1 > /proc/irq/120/smp_affinity # 把中断121绑定到CPU1 echo 2 > /proc/irq/121/smp_affinity # 把中断122绑定到CPU2 echo 4 > /proc/irq/122/smp_affinity # 以此类推,值是2的幂次方,CPU0=1, CPU1=2, CPU2=4, CPU3=8...
如果是8核以上的系统,smp_affinity支持十六进制掩码。比如要绑定到CPU0-7,值就是ff。也可以直接用irqbalance服务自动分配,但在高负载场景下,手动绑定更可控,避免irqbalance频繁调整导致抖动。
五、开启RPS(Receive Packet Steering)
RPS是软件层面的包分发机制,它不需要网卡硬件支持多队列也能工作。它的原理是在软中断处理阶段,根据数据包的hash值把包分发到不同的CPU核心上处理。对于不支持多队列的老网卡,RPS是救命稻草;对于支持多队列的新网卡,RPS可以作为补充和兜底。
RPS的配置通过每个网卡接收队列的sysfs文件来完成。假设eth0有8个队列,每个队列对应一个rps_cpus文件:
# 查看有哪些RPS配置文件 ls /sys/class/net/eth0/queues/rx-*/rps_cpus # 给每个队列设置RPS,绑定到所有CPU(用ff表示8核全开) for i in /sys/class/net/eth0/queues/rx-*/rps_cpus; do echo ff > $i done # 或者只绑定到CPU0-3 for i in /sys/class/net/eth0/queues/rx-*/rps_cpus; do echo 0f > $i done
RPS还有一个更高级的兄弟叫RFS(Receive Flow Steering),它比RPS更智能。RPS是按包分发,同一个连接的包可能被分到不同CPU,导致缓存失效。RFS则是按流(flow)分发,同一个TCP/UDP连接的包始终由同一个CPU处理,大幅提升缓存命中率。
六、开启RFS(Receive Flow Steering)
RFS需要内核版本2.6.35以上,CentOS 7的3.10内核完全支持。开启RFS需要先设置rps_sock_flow_entries,这个参数控制RFS维护的流表大小,值越大支持的并发连接数越多:
# 设置RFS流表大小为32768 echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_sock_flow_entries # 对所有队列都设置 for i in /sys/class/net/eth0/queues/rx-*/rps_sock_flow_entries; do echo 32768 > $i done
RFS的核心逻辑是:当一个CPU处理某个流的数据包时,如果发现这个流的处理负载超过了阈值,内核会自动把这个流迁移到负载较低的CPU上。这个阈值通过rps_flow_cnt参数控制,默认值一般就够用,高负载场景可以调大:
# 设置流迁移阈值(默认是2,表示处理2个包后判断是否迁移) for i in /sys/class/net/eth0/queues/rx-*/rps_flow_cnt; do echo 10 > $i done
七、sysctl参数层面的全局调优
除了针对单个网卡的配置,还有一些全局sysctl参数对网络软中断性能有影响。编辑/etc/sysctl.conf,加入以下配置:
# 增大网络设备接收队列长度,防止高负载时丢包 net.core.netdev_max_backlog = 30000 # 增大默认接收缓冲区 net.core.rmem_default = 262144 net.core.rmem_max = 16777216 # 增大默认发送缓冲区 net.core.wmem_default = 262144 net.core.wmem_max = 16777216 # 增大TCP接收缓冲区 net.ipv4.tcp_rmem = 4096 87380 16777216 net.ipv4.tcp_wmem = 4096 65536 16777216 # 开启TCP窗口缩放 net.ipv4.tcp_window_scaling = 1 # 增大半开连接队列 net.ipv4.tcp_max_syn_backlog = 65536 # 减少TIME_WAIT socket重用等待时间 net.ipv4.tcp_tw_reuse = 1 # 增大somaxconn net.core.somaxconn = 65535 # 开启RPS(全局开关,某些内核需要) net.core.rps_sock_flow_entries = 32768
配置完之后执行sysctl -p生效。这些参数不是孤立的,它们配合网卡队列、RPS、RFS一起工作,形成完整的性能优化链条。
八、实战验证效果
调优完成后,用压测工具验证。推荐用netperf、iperf3或者pktgen来打流量,同时监控软中断分布:
# 实时监控软中断 watch -n 1 cat /proc/softirqs | grep NET_RX # 监控各CPU使用率 mpstat -P ALL 1 # 监控网卡丢包 ifconfig eth0 | grep -i drop ethtool -S eth0 | grep -i drop
如果看到NET_RX均匀分布在多个CPU上,每个核心的softirq占比在合理范围内(比如8核系统每个核心10%-15%),丢包数为零或者极低,那就说明调优成功了。如果还是有瓶颈,检查一下是不是队列数设置超过了网卡硬件支持的上限,或者CPU本身的处理能力已经到顶了,那就需要考虑网卡绑定(bonding)或者升级硬件。
九、常见踩坑点和注意事项
第一,不是所有网卡都支持多队列。用ethtool -l先确认,如果显示只有1个队列,那只能靠RPS来做软件分发,效果会打折扣。第二,RPS和RFS的rps_cpus掩码值要和实际CPU核心数对应,设错了等于没设。第三,虚拟机环境下,vCPU和物理CPU的映射关系会影响亲和性效果,最好在宿主机层面做CPU pinning。第四,别把队列数设得比CPU核心数还多,多余的队列没有CPU处理,反而增加调度开销。第五,调优是个迭代过程,先开多队列,再配RPS,最后加RFS,一步步来,每步都验证,别一次性全改了出问题不知道是哪里的原因。
十、总结
CentOS网卡软中断优化的完整链路是:ethtool开多队列 → 中断亲和性绑定CPU → RPS软件分发 → RFS按流智能分发 → sysctl全局参数兜底。这套方案不需要额外花钱买硬件,纯软件调优就能把单网卡性能榨干。对于高并发Web服务器、数据库中间件、负载均衡节点这些网络密集型场景,这是必须掌握的基本功。记住核心原则:让每个CPU都有事干,别让一个核累死其他核闲着。
