Linux内核软RPS实现网络接收软中断的负载均衡分发

veth网卡的多队列及RPS 3.10内核下容器使用的veth网卡,默认开启的是一个队列,导致在某些单线程多TCP链接的应用场景下,出现某个CPU软中断高的情况。之前处理的方案一直是开启这个veth网卡的RPS,让其在多流场景下可以去分散到其它CPU上,将某个CPU上的软中断降低。其中,skb_get_rx_queue可以通过veth的多队列,拿到不同的队列,但是下面的一个流程,是要配合rps去使用的,所以当前3.10.957的内核即使veth使用了多队列,若没有开rps的话,仍然是返回到当前cpu。带着这个问题看一下内核的处理流程。 阅读详情

例行的Linux软中断分发机制与问题
Linux的中断分为上下两半部,一般而言(事实确实也是如此),被中断的CPU执行中断处理函数,并在在本CPU上触发软中断(下半部),等硬中断处理返回后,软中断随即开中断在本CPU运行,或者wake up本CPU上的软中断内核线程来处理在硬中断中pending的软中断。
       换句话说,Linux和同一个中断向量相关的中断上半部和软中断都是在同一个CPU上执行的,这个可以通过raise_softirq这个接口看出来。这种设计的逻辑是正确的,但是在某些不甚智能的硬件前提下,它工作得并不好。内核没有办法去控制软中断的分发,因此也就只能对硬中断的发射听之任之。这个分为两类情况:
1.硬件只能中断一个CPU
按照上述逻辑,如果系统存在多个CPU核心,那么只能由一个CPU处理软中断了,这显然会造成系统负载在各个CPU间不均衡。
2.硬件盲目随机中断多个CPU
注意”盲目“一词。这个是和主板以及总线相关的,和中断源关系并不大。因此具体中断哪个CPU和中断源的业务逻辑也无关联,比如主板和中断控制器并不是理会网卡的数据包内容,更不会根据数据包的元信息中断不同的CPU...即,中断源对中断哪个CPU这件事可以控制的东西几乎没有。为什么必须是中断源呢?因此只有它知道自己的业务逻辑,这又是一个端到端的设计方案问题。
       因此,Linux关于软中断的调度,缺乏了一点可以控制的逻辑,少了一点灵活性,完全就是靠着硬件中断源中断的CPU来,而这方面,硬件中断源由于被中断控制器和总线与CPU隔离了,它们之间的配合并不好。因此,需要加一个软中断调度层来解决这个问题。
       本文描述的并不是针对以上问题的一个通用的方案,因为它只是针对为网络数据包处理的,并且RPS在被google的人设计之初,其设计是高度定制化的,目的很单一,就是提高Linux服务器的性能。而我,将这个思路移植到了提高Linux路由器的性能上。

基于RPS的软中断分发优化
在Linux转发优化那篇文章《Linux转发性能评估与优化(转发瓶颈分析与解决方案)》中,我尝试了网卡接收软中断的负载均衡分发,当时尝试了将该软中断再次分为上下半部:
上半部:用于skb在不同的CPU间分发。
下半部:用户skb的实际协议栈接收处理。
事实上,利用Linux 2.6.35以后加入的RPS的思想可能会有更好的做法,根本不用重新分割网络接收软中断。它基于以下的事实:
事实1:网卡很高端的情况
如果网卡很高端,那么它一定支持硬件多队列特性以及多中断vector,这样的话,就可以直接绑定一个队列的中断到一个CPU核心,无需软中断重分发skb。
事实2:网卡很低档的情况
如果网卡很低档,比如它不支持多队列,也不支持多个中断vector,且无法对中断进行负载均衡,那么也无需让软中断来分发,直接要驱动里面分发岂不更好(其实这样做真的不好)?事实上,即便支持单一中断vector的CPU间负载均衡,最好也要禁掉它,因为它会破坏CPU cache的亲和力。

为什么以上的两点事实不能利用
中断中不能进行复杂耗时操作,不能由复杂计算。中断处理函数是设备相关的,一般不由框架来负责,而是由驱动程序自己负责。协议栈主框架只维护一个接口集,而驱动程序可以调用接口集内的API。你能保证驱动的编写人员可以正确利用RPS而不是误用它吗?
       正确的做法就是将这一切机制隐藏起来,外部仅仅提供一套配置,你(驱动编写人员)可以开启它,关闭它,至于它怎么工作的,你不用关心。
       因此,最终的方案还是跟我最初的一样,看来RPS也是这么个思路。修改软中断路径中NAPI poll回调!然而poll回调也是驱动维护的,因此就在数据包数据的公共路径上挂接一个HOOK,来负责RPS的处理。

为什么要禁掉低端网卡的CPU中断负载均衡
答案似乎很简单,答案是:因为我们自己用软件可以做得更好!而基于简单硬件的单纯且愚蠢的盲目中断负载均衡可能会(几乎一定会)弄巧成拙!
       这是为什么?因为简单低端网卡硬件不识别网络流,即它只能识别到这是一个数据包,而不能识别到数据包的元组信息。如果一个数据流的第一个数据包被分发到了CPU1,而第二个数据包分发到了CPU2,那么对于流的公共数据,比如nf_conntrack中记录的东西,CPU cache的利用率就会比较低,cache抖动会比较厉害。对于TCP流而言,可能还会因为TCP串行包并行处理的延迟不确定性导致数据包乱序。因此最直接的想法就是将属于一个流的所有数据包分发了一个CPU上。

我对原生RPS代码的修改
要知道,Linux的RPS特性是google人员引入的,他们的目标在于提升服务器的处理效率。因此他们着重考虑了以下的信息:
哪个CPU在为这个数据流提供服务;
哪个CPU被接收了该流数据包的网卡所中断;
哪个CPU运行处理该流数据包的软中断。
理想情况,为了达到CPU cache的高效利用,上面的三个CPU应该是同一个CPU。而原生RPS实现就是这个目的。当然,为了这个目的,内核中不得不维护一个”流表“,里面记录了上面三类CPU信息。这个流表并不是真正的基于元组的流表,而是仅仅记录上述CPU信息的表。
       而我的需求则不同,我侧重数据转发而不是本地处理。因此我的着重看的是:
哪个CPU被接收了该流数据包的网卡所中断;
哪个CPU运行处理该流数据包的软中断。
其实我并不看中哪个CPU调度发送数据包,发送线程只是从VOQ中调度一个skb,然后发送,它并不处理数据包,甚至都不会去访问数据包的内容(包括协议头),因此cache的利用率方面并不是发送线程首要考虑的。
       因此相对于Linux作为服务器时关注哪个CPU为数据包所在的流提供服务,Linux作为路由器时哪个CPU数据发送逻辑可以忽略(虽然它也可以通过设置二级缓存接力[最后讲]来优化一点)。Linux作为路由器,所有的数据一定要快,一定尽可能简单,因为它没有Linux作为服务器运行时服务器处理的固有延迟-查询数据库,业务逻辑处理等,而这个服务处理的固有延迟相对网络处理处理延迟而言,要大得多,因此作为服务器而言,网络协议栈处理并不是瓶颈。服务器是什么?服务器是数据包的终点,在此,协议栈只是一个入口,一个基础设施。
       在作为路由器运行时,网络协议栈处理延迟是唯一的延迟,因此要优化它!路由器是什么?路由器不是数据包的终点,路由器是数据包不得不经过,但是要尽可能快速离开的地方!
       所以我并没有直接采用RPS的原生做法,而是将hash计算简化了,并且不再维护任何状态信息,只是计算一个hash:

target_cpu = my_hash(source_ip, destination_ip, l4proto, sport, dport) % NR_CPU;

[my_hash只要将信息足够平均地进行散列即可!]
仅此而已。于是get_rps_cpu中就可以仅有上面的一句即可。
       这里有一个复杂性要考虑,如果收到一个IP分片,且不是第一个,那么就取不到四层信息,因为可能会将它们和片头分发到不同的CPU处理,在IP层需要重组的时候,就会涉及到CPU之间的数据互访和同步问题,这个问题目前暂不考虑。

NET RX软中断负载均衡总体框架
本节给出一个总体的框架,网卡很低端,假设如下:
不支持多队列;
不支持中断负载均衡;
只会中断CPU0。

它的框架如下图所示:


CPU亲和接力优化
本节稍微提一点关于输出处理线程的事,由于输出处理线程逻辑比较简单,就是执行调度策略然后有网卡发送skb,它并不会频繁touch数据包(请注意,由于采用了VOQ,数据包在放入VOQ的时候,它的二层信息就已经封装好了,部分可以采用分散/聚集IO的方式,如果不支持,只能memcpy了...),因此CPU cache对它的意义没有对接收已经协议栈处理线程的大。然而不管怎样,它还是要touch这个skb一次的,为了发送它,并且它还要touch输入网卡或者自己的VOQ,因此CPU cache如果与之亲和,势必会更好。
       为了不让流水线单独的处理过长,造成延迟增加,我倾向于将输出逻辑放在一个单独的线程中,如果CPU核心够用,我还是倾向于将其绑在一个核心上,最好不要绑在和输入处理的核心同一个上。那么绑在哪个或者哪些上好呢?
       我倾向于共享二级cache或者三级cache的CPU两个核心分别负责网络接收处理和网络发送调度处理。这就形成了一种输入输出的本地接力。按照主板构造和一般的CPU核心封装,可以用下图所示的建议:


为什么我不分析代码实现
第一,基于这样的事实,我并没有完全使用RPS的原生实现,而是对它进行了一些修正,我并没有进行复杂的hash运算,我放宽了一些约束,目的是使得计算更加迅速,无状态的东西根本不需要维护!
第二,我发现我逐渐看不懂我以前写的代码分析了,同时也很难看明白大批批的代码分析的书,我觉得很难找到对应的版本和补丁,但是基本思想却是完全一样的。因此我比较倾向于整理出事件被处理的流程,而不是单纯的去分析代码。
声明:本文是针对底端通用设备的最后补偿,如果有硬件结合的方案,自然要忽略本文的做法。

Linux·图解Linux网络包接收过程 图解Linux网络包接收过程 阅读详情

相关推荐

linux 网络软中断 softirq 底层机制及并发优化

目录 1 软中断 2网络软中断定义 3软中断调用(__napi_schedule) 3.1 唤醒中断 ( __raise_softirq_irqoff ) 4触发软中断 5 收发包软中断执行 6并行优化 6.1RSS/RPS/RFS/XPS 6.1.1 RSS (Receive Side Scaling) (接收侧的缩放) 6.1.2 RPS Receive Packet Steering (接收端包的控制) 6.1.3 RFS Receive Flow Steeri...

6159

linux网络RPS RFS流程分析

raw_smp_processor_id() 函数通常在内核编程中使用,并且在内核的多 CPU 相关的代码中是比较常见的。需要注意的是,raw_smp_processor_id() 函数是一个非常底层的函数,直接返回当前 CPU 的物理 ID,没有进行任何锁定或同步操作。raw_smp_processor_id() 函数允许内核代码获取当前 CPU 的物理 ID,从而可以在多 CPU 的环境中进行处理器相关的操作,例如分配特定的资源、调度任务到特定的 CPU 等。

OS Developer的博客 970

linux 网络RPS/RFS/XPS

1. 介绍 在网络非常 heavy 的情况下,对于文件服务器、高流量 Web 服务器这样的应用来说,把不同的网卡 IRQ 均衡绑定到不同的 CPU 上将会减轻某个 CPU 的负担,提高多个 CPU 整体处理中断的能力; 对于数据库服务器这样的应用来说,把磁盘控制器绑到一个 CPU、把网卡绑定到另一个 CPU 将会提高数据库的响应时间、优化性能。合理的根据自己的生产环境和应用的特点来平衡 IRQ 中断有助于提高系统的整体吞吐能力和性能。 以网卡中断为例,在没有设置SMP IRQ affini...

ARM-Linux 2205

linux 内核rps,Linux kernel之网络rps

Linux kernel之网络rpsrps即receive package scaling, 是内核软件层实现的一个性能扩展机制,根据网络包数据计算hash值,然后挂载到对应cpu的backlog队列中,代码如下:static int netif_rx_internal(struct sk_buff *skb){int ret;net_timestamp_check(netdev_tstamp_p...

weixin_42203424的博客 1728

从时序精度到视觉盛宴:PY32F030驱动WS2812的工程艺术与避坑指南

本文深入探讨了基于PY32F030微控制器驱动WS2812智能LED的完整解决方案。通过精确的时序控制、硬件PWM结合DMA传输技术,实现了稳定可靠的驱动效果,并提供了电源管理、信号完整性和常见问题排查等实用避坑指南,帮助开发者轻松应对严格的纳秒级时序挑战。

wind6的博客 120

ESP32驱动GC9A01圆形屏实战:Arduino平台LVGL移植与图像显示优化

本文详细介绍了在Arduino平台上使用ESP32驱动GC9A01圆形屏的实战指南,包括硬件连接、LVGL移植与图像显示优化。通过SPI配置、LVGL库安装和双缓冲机制等技巧,帮助开发者快速实现高效显示效果,适用于智能家居控制面板等应用场景。

weixin_29182481的博客 733

linux 内核rps,Linux内核软RPS实现网络接收软中断的负载均衡分发

例行的Linux软中断分发机制与问题Linux的中断分为上下两半部,一般而言(事实确实也是如此),被中断的CPU执行中断处理函数,并在在本CPU上触发软中断(下半部),等硬中断处理返回后,软中断随即开中断在本CPU运行,或者wake up本CPU上的软中断内核线程来处理在硬中断中pending的软中断。换句话说,Linux和同一个中断向量相关的中断上半部和软中断都是在同一个CPU上执行的,这个可以...

weixin_31312621的博客 786

京东前端200道面试题及参考答案(中)

前端优化是“提升用户体验、降低资源消耗”的核心手段,需围绕“用户感知的性能指标”(如页面加载速度、交互流畅度)展开,覆盖加载优化、渲染优化、代码优化、网络优化、缓存优化、性能监控六大维度,每个维度下有具体可落地的措施,同时需结合项目实际场景(如单页应用、电商首页)选择优化方案。分页组件需通过props接收“数据总量、当前页、每页条数”等基础信息,通过emit触发“页码切换、每页条数变化”的回调(供父组件请求对应页数据),同时定义默认值确保兼容性。核心Props与Emit设计<template>

大模型大数据攻城狮的专栏 588

linux 内核网络中 RPS/RFS 原理Ⅰ

目录 1 自带 irqbalance 瓶颈 2 RPS/RFS 数据结构以及更新函数 2.1 CPU 负载表 rps_map 2.1.1rps_map 解析函数(store_rps_map) 2.2设备流表 rps_dev_flow_table 2.2.1 设备流表初始化函数 store_rps_dev_flow_table_cnt 2.3全局的数据流表(rps_sock_flow_table) 2.3.1 全局流表更新函数 ( rps_record_sock_flow ) 3RP...

2046

uniapp - 超详细 H5 网页利用 uni.downloadFile 下载 URL 文件流并调用浏览器下载功能效果,前台通过请求后端接口获取文件并下载保存到本地(支持电脑PC与手机移动端H5)

uniapph5网页下载文件,uniapp网站下载文件流,uniapp的移动端h5实现接口url文件下载,uniapph5页面在浏览器中如何下载指定url文件流文件并保存到本地,uniapp移动端h5调用后端接口保存文件到本地,uniapph5通过下载后获得临时路径怎么让浏览器弹出下载,uniapp怎么请求接口下载到文件,得到Blob临时路径对象后如何下载到本地,浏览器怎么下载blob对象,uniapp二进制文件流下载,uniapph5中的文件流下载和指定的url下载详细教程,uniappapp移

🏆 前端领域优质创作者 1万+

YOLOv11涨点改进| CVPR 2026 | 全网独家首发、特征融合改进篇| 引入SRFusion 空间细化多级融合,含多种创新融合改进,涨点可直接发论文,适合裂缝图像检测,小目标检测任务高效涨点

🔥本文提出SRFusion空间细化多级融合模块,用于改进YOLOv11网络模型。该模块通过高分辨率特征引导低分辨率语义特征的融合,利用空间注意力机制对上采样后的特征进行加权细化,增强多尺度特征间的空间细节交互。SRFusion模块能够提升模型对目标区域的表达能力,有效改善小目标、密集目标及复杂背景场景下的检测效果,同时保持YOLOv11的高效性与实时检测性能。文章详细介绍了模块结构、实现原理、核心代码及在YOLOv11中的三种配置方法,为模型优化提供了创新解决方案。

Ai缝合怪、助力小伙伴高效发论文 147

Linux内核 RPS/RFS功能详细测试分析

http://www.igigo.net/archives/204 IGI's Blog RSS 订阅 Linux内核 RPS/RFS功能详细测试分析 作者: igi 日期: 2012/05/31 发表评论 (1)查看评论 RPS和RFS RPS 全称是 Receive Packet Steering, 这是Google工程师 Tom Herbert (th

Hello World! 1万+

【ArcGIS Pro微课1000例】0022:基于DEM进行流域分析生成流域图

填洼Fill,在进行水文分析后续操作前,首先要对DEM进行填洼,创建无凹陷点的DEM。在ArcGIS中使用的是八方向流量建模(D8算法),工具位于水文分析下的【流向】。填洼需要使用水文分析工具下的【填洼】。确定输入与输出即可。

智慧空间实验室 2749

Linux 网络:RPS 简介

Linux,网络,RPS & RFS

JiMoKuangXiangQu的专栏 815

基于pytorch cnn ResNets卷积网络的模糊图像检测 完整代码数据直接运行

基于pytorch cnn ResNets卷积网络的模糊图像检测 完整代码数据直接运行

729

拉曼光谱入门:5.表面增强与共振增强

拉曼散射效应因其弱信号特性限制了传统拉曼光谱术的检测灵敏度。为克服这一局限,表面增强拉曼光谱术(SERS)和共振增强拉曼光谱术(RRS)被开发出来,显著提升了信号强度。SERS通过金属表面的电磁和化学效应放大信号,而RRS则通过匹配激发光波长与分子电子跃迁波长来增强信号。这两种技术扩大了拉曼光谱的应用范围,尤其在低浓度和微量试样分析中表现出色,尽管在实验操作和试样损伤方面存在挑战。

qq_53529450的博客 1446

【独家披露】高频交易系统背后的内核优化逻辑:99%的人忽略的RPS/RFS配置细节

揭秘高频交易低延迟系统的内核参数调优与编程配合,详解RPS/RFS配置在网卡中断优化中的关键作用,显著降低网络延迟。适用于金融交易、实时风控等场景,提升系统响应速度与稳定性,值得收藏。

DeepNest的博客 1089

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

RPS特性

数据结构 RPS接收队列 /* This structure contains an instance of an RX queue. */ struct netdev_rx_queue { // 对应/sys/class/net/网卡/queues/rx-xxx/rps_cpus文件 struct rps_map *rps_map; struct kobject kobj; // 因为可...

九天小哥的专栏 2511

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

一文看懂linux 内核网络中 RPS/RFS 原理

数据对象 softnet_data 中有 backlog 的成员,该成员类型为 struct napi_struct,在函数 enqueue_to_backlog() 中,会将 backlog 加入到 cpu 的待轮询设备列表中,并触发软中断,在软中断处理函数 net_rx_action() 中会依次遍历待轮询设备列表中的设备,并调用设备注册的 poll 回调函数来进行报文处理。当用户态处理报文的 cpu 和内核处理报文软中断的 cpu 不同的时候,就会导致 cpu 的缓存不命中。

m0_74282605的博客 1902

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Linux系统中RPS/RFS介绍

http://blog.chinaunix.net/uid-20788636-id-4838269.html 1  RPS/RFS 介绍 1.1 RPS/RFS出现的原因 RPS/RFS 功能是在Linux- 2.6.35中有google的工程师提交的两个补丁,这两个补丁的出现主要是基于以下两点现实的考虑: (1)       这两个补丁的出现,是由于服务器的CPU越来越强劲,可以到达

IT小小鸟 8215

linux内核网络中RPS/RFS原理

linux内核网络中RPS/RFS原理  在上篇中,从整体上讲解了网络软中断的机制和优化,但是在RPS和RFS处并没有彻底讲清楚,只是描述了其整体功能和涉及初衷。这篇,进一步深度并搞明白RPS和RFS机制。1.1.1 自带irqbalance瓶颈基于简单的中断负载均衡(如系统自带的irqbalance进程)可能会弄巧成拙。因为其并不识别网络流,只识别到这是一个数据包,不能识别到数据包的元组信息。在...

badman250的专栏 1万+

Linux内核网络性能优化

1. 前言 2. Linux网络协议栈 3. DPDK 4. XDP 5. CPU负载均衡 5.1 NAPI 5.2 RSS 5.3 RPS 5.4 RFS 5.5 XPS 6. 网络套接字 7. 总结 参考链接: https://blog.selectel.com/introduction-dpdk-architecture-principles/ https://medium.com/@jain.sm/express-data-path-xdp-introduction-d41b77ffbabf

金荣的个人技术博客 1786
上一篇: Linux VRF(Virtual Routing Forwarding)的原理和实现
下一篇: 真正理解红黑树,真正的
废言Pro
博客等级 码龄16年 1092粉丝 142原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值