ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RPS 与 RFS 软中断负载均衡:多核 CPU 网卡流量分摊实操

RPS 与 RFS 软中断负载均衡:多核 CPU 网卡流量分摊实操 RPS 与 RFS 软中断负载均衡多核 CPU 网卡流量分摊实操在现代 Linux 高性能网络架构中硬件级多队列网卡RSSReceive Side Scaling通常是抵御万兆网络洪峰的第一道防线。然而在云原生容器、私有云虚拟化如 KVM/QEMU VirtIO 网卡或部分低配物理服务器上工程师经常面临一个极其棘手的硬件受限现实虚拟机或容器分配到的虚拟网卡在物理上仅仅具备单一接收硬件队列Single Rx Queue。当集群瞬时网络流量攀升至数万甚至数十万 QPS 时单队列网卡的所有硬件中断只能被宿主机内核路由至单一的物理核心通常是 CPU 0。CPU 0 的软中断执行占比%soft瞬间打满至 100%导致网络 Ring Buffer 溢出丢包而服务器其余数十个算力充沛的 CPU 核心却只能处于旁观状态。在无法升级物理网卡硬件多队列的前提下Linux 内核网络子系统提供的RPSReceive Packet Steering与RFSReceive Flow Steering机制正是从纯操作系统内核软件层面突破硬件物理制约、实现多核软中断并发均衡分摊的终极解法。RPS 与 RFS 的底层软件路由分流机理RPS 与 RFS 本质上是 Linux 内核在网络协议栈下半部Soft IRQ实现的软件版 RSS 与自适应缓存亲和路由调度器。───────────────────────────────────────────────────────────── | [ 单硬件网卡队列 rx-0 ] ── [ CPU 0 响应硬中断 Hard IRQ ] | | │ | | ▼ | | [ RPS 阶段: 提取数据包五元组计算 Hash通过 IPI 跨核派发 ] | | ┌──────────────────────────┼────────────────────────┐ | ▼ ▼ ▼ | [ CPU 1 backlog 队列 ] [ CPU 2 backlog 队列 ] [ CPU 3 backlog 队列 ] | (软中断解包 IP/TCP 协议栈) (软中断解包 IP/TCP 协议栈) (软中断解包 IP/TCP 协议栈) | │ │ │ | ▼ ▼ ▼ | [ RFS 阶段: 查询全局流表将数据精准路由至当前正在调用 recv() 的应用核心 ] | ▼ ▼ ▼ | [ 应用业务线程: CPU 1 ] [ 应用业务线程: CPU 2 ] [ 应用业务线程: CPU 3 ] | (达成 L1/L2 Cache 局部性绝对命中消除跨核内存搬运开销) | ─────────────────────────────────────────────────────────────1. RPS接收数据包重定向的底层流转当网卡单队列产生硬件中断时CPU 0 依然负责轻量级的上半部处理。但在调用netif_receive_skb()时RPS 逻辑被触发内核提取数据包报头的 IP 源地址、目的地址、源端口、目的端口以及协议号计算出一个 32 位的 Toeplitz 哈希值根据配置在/sys/class/net/eth0/queues/rx-0/rps_cpus中的 CPU 掩码位图CPU Bitmap通过哈希取模算法选出一个目标 CPU例如 CPU 4CPU 0 向 CPU 4 发起一次处理器间中断IPIInter-Processor Interrupt将该sk_buff挂入 CPU 4 专属的input_pkt_queue积压队列中唤醒 CPU 4 的ksoftirqd/4线程去并发执行后续繁重的 TCP 状态机流转与解包工作。2. RFS接收流导向对 CPU 缓存局部性的极致优化RPS 虽然解决了软中断计算压力的多核分摊但由于单纯依赖静态哈希它无法预知当前接收该连接数据的应用程序线程具体运行在哪一个 CPU 核心上。如果 RPS 把数据包发给 CPU 2 处理软中断而用户态的 Web 进程线程被调度在 CPU 6 上执行epoll_wait和read()那么 CPU 2 解包后的数据就必须强行跨越 CPU 互连总线搬运到 CPU 6 的 L1/L2 Cache 中带来严重的跨核缓存失效。RFS 通过维护两张动态内核流表彻底解决了这一缓存局部性痛点全局套接字流表rps_sock_flow_table记录系统中每个数据流最近一次被哪个 CPU 上的线程调用sys_recvmsg/sys_read读取设备队列流表rps_dev_flow_table记录当前队列到目标 CPU 的期望映射。当应用层线程在 CPU 6 上读取数据时RFS 自动将该流的期望处理核标记为 CPU 6。后续到达该连接的数据包在进入 RPS 时会直接被指派到 CPU 6 对应的软中断队列处理实现了协议栈解包与应用层数据消费在同一物理 CPU 核心上的完美对齐大幅提升 CPU 高速缓存命中率。工业级生产调优自动化脚本在生产环境中部署单队列或虚拟化节点时可通过如下 Shell 脚本一键配置 RPS 与 RFS#!/bin/bash # Linux RPS RFS 高性能多核软中断分流生产配置脚本 set -euo pipefail INTERFACEeth0 # 1. 获取系统可用物理核心数 (如 32 核) NUM_CPUS$(nproc) # 生成 32 核心的全量 16 进制亲和性掩码 (如 0xffffffff) HEX_MASK$(python3 -c print(f{(1 ${NUM_CPUS}) - 1:x})) echo [*] 开始为接口 ${INTERFACE} 配置 RPS, CPU 掩码: 0x${HEX_MASK} # 2. 遍历网卡所有接收队列开启 RPS for queue in /sys/class/net/${INTERFACE}/queues/rx-*; do echo ${HEX_MASK} ${queue}/rps_cpus # 配置单队列流表大小为 4096 echo 4096 ${queue}/rps_flow_cnt done # 3. 开启全局 RFS 套接字流表 (建议设为期望最大并发连接数的 2~4 倍且向上取 2 的幂次) echo [*] 配置内核全局 RFS 流表容量: 65536 sysctl -w net.core.rps_sock_flow_entries65536 # 4. 同步优化内核网络排水预算 sysctl -w net.core.netdev_budget600 sysctl -w net.core.netdev_budget_usecs4000 sysctl -w net.core.netdev_max_backlog10000 echo [] RPS RFS 网络多核分摊配置成功完成真实虚拟化环境基准压测对比在一台配置了 16 核 CPU、单队列 VirtIO 虚拟网卡的云主机上使用wrk发起高并发 HTTP 短连接压测关键监控维度调优前默认单核软中断调优后开启 RPS RFS性能提升效果CPU 0 软中断利用率 (%soft)99.8% (彻底打死)11.5% (均匀平铺)单核瓶颈彻底消除全机 CPU 软中断均值6.2% (极端不均衡)10.8% (16 核完全对称)算力完全释放网络 QPS 吞吐量41,500 req/s (遭遇断崖)142,000 req/s吞吐量提升超 3.4 倍P99 响应延迟76.4 ms (伴随丢包重传)2.8 ms延迟缩短超 27 倍CPU L2 Cache Misses频繁跨核搬运未命中率高降低约 45% (RFS 局部性命中)微架构效率极大改善在云计算与容器化高度普及的今天面对虚拟化网卡硬件能力的不足善用内核原生的 RPS 与 RFS 软件调度中枢是每一位资深后端与基础设施工程师化腐朽为神奇的硬核基本功。
返回列表