linux rfs rps_linux 开启 rps/rfs - CSDN
  • Linux内核 RPS/RFS功能详细测试分析

    万次阅读 2013-08-08 16:12:59
    RPSRFS RPS 全称是 Receive Packet Steering, 这是Google工程师 Tom Herbert (therbert@google.com )提交的内核补丁, 在2.6.35进入Linux内核. 这个patch采用软件模拟的方式,实现了多队列网卡所提供的功能...

    RPS和RFS

    • RPS 全称是 Receive Packet Steering, 这是Google工程师 Tom Herbert (therbert@google.com )提交的内核补丁, 在2.6.35进入Linux内核. 这个patch采用软件模拟的方式,实现了多队列网卡所提供的功能,分散了在多CPU系统上数据接收时的负载, 把软中断分到各个CPU处理,而不需要硬件支持,大大提高了网络性能。
    • RFS 全称是 Receive Flow Steering, 这也是Tom提交的内核补丁,它是用来配合RPS补丁使用的,是RPS补丁的扩展补丁,它把接收的数据包送达应用所在的CPU上,提高cache的命中率。
    • 这两个补丁往往都是一起设置,来达到最好的优化效果, 主要是针对单队列网卡多CPU环境(多队列多重中断的网卡也可以使用该补丁的功能,但多队列多重中断网卡有更好的选择:SMP IRQ affinity)

    原理

    RPS: RPS实现了数据流的hash归类,并把软中断的负载均衡分到各个cpu,实现了类似多队列网卡的功能。由于RPS只是单纯的把同一流的数据包分发给同一个CPU核来处理了,但是有可能出现这样的情况,即给该数据流分发的CPU核和执行处理该数据流的应用程序的CPU核不是同一个:数据包均衡到不同的cpu,这个时候如果应用程序所在的cpu和软中断处理的cpu不是同一个,此时对于cpu cache的影响会很大。那么RFS补丁就是用来确保应用程序处理的cpu跟软中断处理的cpu是同一个,这样就充分利用cpu的cache。

    • 应用RPS之前: 所有数据流被分到某个CPU, 多CPU没有被合理利用, 造成瓶颈

    • 应用RPS之后: 同一流的数据包被分到同个CPU核来处理,但可能出现cpu cache迁跃

    • 应用RPS+RFS之后: 同一流的数据包被分到应用所在的CPU核

    必要条件

    使用RPS和RFS功能,需要有大于等于2.6.35版本的Linux kernel.

    如何判断内核版本?

    1
    2
    $ uname -r
    2.6.38-2-686-bigmem

    对比测试

    类别 测试客户端 测试服务端
    型号 BladeCenter HS23p BladeCenter HS23p
    CPU Xeon E5-2609 Xeon E5-2630
    网卡 Broadcom NetXtreme II BCM5709S Gigabit Ethernet Emulex Corporation OneConnect 10Gb NIC
    内核 3.2.0-2-amd64 3.2.0-2-amd64
    内存 62GB 66GB
    系统 Debian 6.0.4 Debian 6.0.5
    超线程
    CPU核 4 6
    驱动 bnx2 be2net
    • 客户端: netperf
    • 服务端: netserver
    • RPS cpu bitmap测试分类: 0(不开启rps功能), one cpu per queue(每队列绑定到1个CPU核上), all cpus per queue(每队列绑定到所有cpu核上), 不同分类的设置值如下
    1. 0(不开启rps功能)
      /sys/class/net/eth0/queues/rx-0/rps_cpus 00000000
      /sys/class/net/eth0/queues/rx-1/rps_cpus 00000000
      /sys/class/net/eth0/queues/rx-2/rps_cpus 00000000
      /sys/class/net/eth0/queues/rx-3/rps_cpus 00000000
      /sys/class/net/eth0/queues/rx-4/rps_cpus 00000000
      /sys/class/net/eth0/queues/rx-5/rps_cpus 00000000
      /sys/class/net/eth0/queues/rx-6/rps_cpus 00000000
      /sys/class/net/eth0/queues/rx-7/rps_cpus 00000000
      
      /sys/class/net/eth0/queues/rx-0/rps_flow_cnt 0
      /sys/class/net/eth0/queues/rx-1/rps_flow_cnt 0
      /sys/class/net/eth0/queues/rx-2/rps_flow_cnt 0
      /sys/class/net/eth0/queues/rx-3/rps_flow_cnt 0
      /sys/class/net/eth0/queues/rx-4/rps_flow_cnt 0
      /sys/class/net/eth0/queues/rx-5/rps_flow_cnt 0
      /sys/class/net/eth0/queues/rx-6/rps_flow_cnt 0
      /sys/class/net/eth0/queues/rx-7/rps_flow_cnt 0
      
      /proc/sys/net/core/rps_sock_flow_entries 0
    2. one cpu per queue(每队列绑定到1个CPU核上)
      /sys/class/net/eth0/queues/rx-0/rps_cpus 00000001
      /sys/class/net/eth0/queues/rx-1/rps_cpus 00000002
      /sys/class/net/eth0/queues/rx-2/rps_cpus 00000004
      /sys/class/net/eth0/queues/rx-3/rps_cpus 00000008
      /sys/class/net/eth0/queues/rx-4/rps_cpus 00000010
      /sys/class/net/eth0/queues/rx-5/rps_cpus 00000020
      /sys/class/net/eth0/queues/rx-6/rps_cpus 00000040
      /sys/class/net/eth0/queues/rx-7/rps_cpus 00000080
      
      /sys/class/net/eth0/queues/rx-0/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-1/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-2/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-3/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-4/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-5/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-6/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-7/rps_flow_cnt 4096
      
      /proc/sys/net/core/rps_sock_flow_entries 32768
    3. all cpus per queue(每队列绑定到所有cpu核上)
      /sys/class/net/eth0/queues/rx-0/rps_cpus 000000ff
      /sys/class/net/eth0/queues/rx-1/rps_cpus 000000ff
      /sys/class/net/eth0/queues/rx-2/rps_cpus 000000ff
      /sys/class/net/eth0/queues/rx-3/rps_cpus 000000ff
      /sys/class/net/eth0/queues/rx-4/rps_cpus 000000ff
      /sys/class/net/eth0/queues/rx-5/rps_cpus 000000ff
      /sys/class/net/eth0/queues/rx-6/rps_cpus 000000ff
      /sys/class/net/eth0/queues/rx-7/rps_cpus 000000ff
      
      /sys/class/net/eth0/queues/rx-0/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-1/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-2/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-3/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-4/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-5/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-6/rps_flow_cnt 4096
      /sys/class/net/eth0/queues/rx-7/rps_flow_cnt 4096
      
      /proc/sys/net/core/rps_sock_flow_entries 32768

    测试方法: 每种测试类型执行3次,中间睡眠10秒, 每种测试类型分别执行100、500、1500个实例, 每实例测试时间长度为60秒

    • TCP_RR 1 byte: 测试TCP 小数据包 request/response的性能
      1
      netperf -t TCP_RR -H $serverip -c -C -l 60
    • UDP_RR 1 byte: 测试UDP 小数据包 request/response的性能
      1
      netperf -t UDP_RR -H $serverip -c -C -l 60
    • TCP_RR 256 byte: 测试TCP 大数据包 request/response的性能
      1
      netperf -t TCP_RR -H $serverip -c -C -l 60 -- -r256,256
    • UDP_RR 256 byte: 测试UDP 大数据包 request/response的性能
      1
      netperf -t UDP_RR -H $serverip -c -C -l 60 -- -r256,256

    TPS测试结果

    • TCP_RR 1 byte小包测试结果

    • TCP_RR 256 byte大包测试结果

    • UDP_RR 1 byte小包测试结果

    • UDP_RR 256 byte大包测试结果

    CPU负载变化

    在测试过程中,使用mpstat收集各个CPU核的负载变化

    1. 关闭RPS/RFS: 可以看出关闭RPS/RFS时,软中断的负载都在cpu0上,并没有有效的利用多CPU的特性,导致了性能瓶颈
      Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
      Average:     all    3.65    0.00   35.75    0.05    0.01   14.56    0.00    0.00   45.98
      Average:       0    0.00    0.00    0.00    0.00    0.00  100.00    0.00    0.00    0.00
      Average:       1    4.43    0.00   37.76    0.00    0.11   11.49    0.00    0.00   46.20
      Average:       2    5.01    0.00   45.80    0.00    0.00    0.00    0.00    0.00   49.19
      Average:       3    5.11    0.00   45.07    0.00    0.00    0.00    0.00    0.00   49.82
      Average:       4    3.52    0.00   40.38    0.14    0.00    0.00    0.00    0.00   55.96
      Average:       5    3.85    0.00   39.91    0.00    0.00    0.00    0.00    0.00   56.24
      Average:       6    3.62    0.00   40.48    0.14    0.00    0.00    0.00    0.00   55.76
      Average:       7    3.87    0.00   38.86    0.11    0.00    0.00    0.00    0.00   57.16
    2. 每队列关联到一个CPU TCP_RR: 可以看出软中断负载已经能分散到各个CPU核上,有效利用了多CPU的特性,大大提高了系统的网络性能
      Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
      Average:     all    5.58    0.00   59.84    0.01    0.00   22.71    0.00    0.00   11.86
      Average:       0    2.16    0.00   20.85    0.00    0.04   72.03    0.00    0.00    4.93
      Average:       1    4.68    0.00   46.27    0.00    0.00   42.73    0.00    0.00    6.32
      Average:       2    6.76    0.00   63.79    0.00    0.00   11.03    0.00    0.00   18.42
      Average:       3    6.61    0.00   65.71    0.00    0.00   11.51    0.00    0.00   16.17
      Average:       4    5.94    0.00   67.83    0.07    0.00   11.59    0.00    0.00   14.58
      Average:       5    5.99    0.00   69.42    0.04    0.00   12.54    0.00    0.00   12.01
      Average:       6    5.94    0.00   69.41    0.00    0.00   12.86    0.00    0.00   11.78
      Average:       7    6.13    0.00   69.61    0.00    0.00   14.48    0.00    0.00    9.77
    3. 每队列关联到一个CPU UDP_RR: CPU负载未能均衡的分布到各个CPU, 这是由于网卡hash计算在UDP包上的不足, 详细请见本文后记部分
      Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
      Average:     all    3.01    0.00   29.84    0.07    0.01   13.35    0.00    0.00   53.71
      Average:       0    0.00    0.00    0.08    0.00    0.00   90.01    0.00    0.00    9.91
      Average:       1    3.82    0.00   32.87    0.00    0.05   12.81    0.00    0.00   50.46
      Average:       2    4.84    0.00   37.53    0.00    0.00    0.14    0.00    0.00   57.49
      Average:       3    4.90    0.00   37.92    0.00    0.00    0.16    0.00    0.00   57.02
      Average:       4    2.57    0.00   32.72    0.20    0.00    0.09    0.00    0.00   64.42
      Average:       5    2.66    0.00   33.54    0.11    0.00    0.08    0.00    0.00   63.60
      Average:       6    2.75    0.00   32.81    0.09    0.00    0.06    0.00    0.00   64.30
      Average:       7    2.71    0.00   32.66    0.17    0.00    0.06    0.00    0.00   64.40
    4. 每队列关联到所有CPU: 可以看出软中断负载已经能分散到各个CPU核上,有效利用了多CPU的特性,大大提高了系统的网络性能
      Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
      Average:     all    5.39    0.00   59.97    0.00    0.00   22.57    0.00    0.00   12.06
      Average:       0    1.46    0.00   21.83    0.04    0.00   72.08    0.00    0.00    4.59
      Average:       1    4.45    0.00   46.40    0.00    0.04   43.39    0.00    0.00    5.72
      Average:       2    6.84    0.00   65.62    0.00    0.00   11.39    0.00    0.00   16.15
      Average:       3    6.71    0.00   67.13    0.00    0.00   12.07    0.00    0.00   14.09
      Average:       4    5.73    0.00   66.97    0.00    0.00   10.71    0.00    0.00   16.58
      Average:       5    5.74    0.00   68.57    0.00    0.00   13.02    0.00    0.00   12.67
      Average:       6    5.79    0.00   69.27    0.00    0.00   12.31    0.00    0.00   12.63
      Average:       7    5.96    0.00   68.98    0.00    0.00   12.00    0.00    0.00   13.06

    结果分析

    以下结果只是针对测试服务器特定硬件及系统的数据,在不同测试对象的RPS/RFS测试结果可能有不同的表现

    TCP性能:

    • 在没有打开RPS/RFS的情况下,随着进程数的增加,TCP tps性能并明显没有提升,在184~188k之间。
    • 打开RPS/RFS之后,随着RPS导致软中断被分配到所有CPU上和RFS增加的cache命中, 小数据包(1字节)及大数据包(256字节,相对小数据包而言, 而不是实际应用中的大数据包)的tps性能都有显著提升
    • 100个进程提升40%的性能(两种RPS/RFS设置的性能结果一致), cpu负载升高40%
    • 500个进程提升70%的性能(两种RPS/RFS设置的性能结果一致), cpu负载升高62%
    • 1500个进程提升75%的性能(两种RPS/RFS设置的性能结果一致), cpu负载升高77%



    UDP性能:

    • 在没有打开RPS/RFS的情况下,随着进程数的增加,UDP tps性能并明显没有提升,在226~235k之间。
    • 打开RPS/RFS之后,,随着RPS导致软中断被分配到所有CPU上和RFS增加的cache命中, 小数据包(1字节)及大数据包(256字节,相对小数据包而言, 而不是实际应用中的大数据包)的TPS性能, 在每队列关联到所有CPU的情况下有显著提升, 而每队列关联到一个CPU后反倒是导致了UDP tps性能下降1% (这是bnx2网卡不支持UDP port hash及此次测试的局限性造成的结果, 详细分析见: 后记)
    • 每队列关联到所有CPU的情况下, 在100个进程时小包提升40%的性能, cpu负载升高60%; 大包提升33%, cpu负载升高47%
    • 每队列关联到所有CPU的情况下, 在500个进程提小包提升62%的性能, cpu负载升高71%; 大包提升60%, cpu负载升高65%
    • 每队列关联到所有CPU的情况下, 在1500个进程提升65%的性能, cpu负载升高75%; 大包提升64%, cpu负载升高74%

    后记

    UDP在每队列绑定到一个CPU时性能下降,而绑定到所有CPU时,却有性能提升,这一问题涉及到几个因素,当这几个因素凑一起时,导致了这种奇特的表现。

    • 此次测试的局限性:本次测试是1对1的网络测试,产生的数据包的IP地址都是相同的
    • bnx2网卡在RSS hash上,不支持UDP Port,也就是说,网卡在对TCP数据流进行队列选择时的hash包含了ip和port, 而在UDP上的hash, 只有IP地址,导致了本次测试(上面的局限性影响)的UDP数据包的hash结果都是一样的,数据包被转送到同一条队列。
    • 单单上面两个因素,还无法表现出UDP在每队列绑定到一个CPU时性能下降,而绑定到所有CPU时,却有性能提升的现象。 因为RPS/RFS本身也有hash计算,也就是进入队列后的数据包,还需要经过RPS/RFS的hash计算(这里的hash支持udp port), 然后进行第二次数据包转送选择;如果每队列绑定到一个CPU, 系统直接跳过第二次hash计算,数据包直接分配到该队列关联的CPU处理,也就导致了在第一次hash计算后被错误转送到某一队列的UDP数据包,将直接送到cpu处理,导致了性能的下降; 而如果是每队列绑定到所有CPU, 那么进入队列后的数据包会在第二次hash时被重新分配,修正了第一次hash的错误选择。

    相关对比测试

    1. SMP IRQ affinity: http://www.igigo.net/archives/231

    参考资料


    展开全文
  • linux内核网络中RPS/RFS原理

    千次阅读 2018-03-20 19:58:13
    linux内核网络中RPS/RFS原理 在上篇中,从整体上讲解了网络软中断的机制和优化,但是在RPSRFS处并没有彻底讲清楚,只是描述了其整体功能和涉及初衷。这篇,进一步深度并搞明白RPSRFS机制。1.1.1 自带irq...

    linux内核网络中RPS/RFS原理

      在上篇中,从整体上讲解了网络软中断的机制和优化,但是在RPS和RFS处并没有彻底讲清楚,只是描述了其整体功能和涉及初衷。这篇,进一步深度并搞明白RPS和RFS机制。

    1.1.1 自带irqbalance瓶颈

    基于简单的中断负载均衡(如系统自带的irqbalance进程)可能会弄巧成拙。因为其并不识别网络流,只识别到这是一个数据包,不能识别到数据包的元组信息。

    在多处理器系统的每个处理器都有单独的硬件高速缓存,如果其中一个CPU修改了自己的硬件高速缓存,它就必须该数据是否包含在其它CPU的硬件高速缓存,如果存在,必须通知其它CPU更新硬件高速缓存,这叫做CPU的cache一致性。所以为了降低CPU硬件高速缓存的刷新频率,需要把特征相似的数据包分配给同一个CPU处理。

    另外在TCP的IP包的分段重组问题,一旦乱序就要重传,一个linux主机如果只是作为一台路由器的话,那么进入系统的一个TCP包的不同分段如果被不同的cpu处理并向一个网卡转发了,那么同步问题会很麻烦的,如果不做同步处理,那么很可能后面的段被一个cpu先发出去了,那最后接收方接收到乱序的包后就会请求重发,这样则还不如是一个cpu串行处理。

                这个需要一套方案,需要弄清楚三个问题:

    l   哪个CPU在消耗这个网络数据

    l   哪个CPU在处理中断

    l   哪个CPU在做软中断

    这个三个问题就是RPS/RFS需要去解决的。

    1.1.2 数据结构

      linux底层的很多机密都藏在数据结构中,包括其面向对象的设计。所以先来看下这些数据结构。

    网卡的硬件接收队列netdev_rx_queue, 定义在文件:

    include/linux/netdevice.h中。

    struct netdev_rx_queue {

    #ifdef CONFIG_RPS

            struct rps_map __rcu            *rps_map;

            struct rps_dev_flow_table __rcu *rps_flow_table;

    #endif

            struct kobject                  kobj;

            struct net_device               *dev;

            struct xdp_rxq_info             xdp_rxq;

    } ____cacheline_aligned_in_smp;

      存放解析结果的就是网卡硬件接收队列实例的rps_map成员, cpus数组用来记录配置文件中配置的参与报文分发处理的cpu的数组,而len成员就是cpus数组的长度。解析函数为store_rps_map定义在文件net/core/net-sysfs.c中。

    /*

     * This structure holds an RPS map which can be of variable length.  The

     * map is an array of CPUs.

     */

    struct rps_map {

            unsigned int len;

            struct rcu_head rcu;

            u16 cpus[0];

    };

      设备流表rps_dev_flow_table,定义在文件:include/linux/netdevice.h中。mask成员是类型为struct rps_dev_flow的数组的大小,也就是流表项的数目,通过配置文件 /sys/class/net/(dev)/queues/rx-(n)/rps_flow_cnt进行指定的。当设置了配置文件,那么内核就会获取到数据,并初始化网卡硬件接收队列中的设备流表成员rps_flow_table(初始化过程函数store_rps_dev_flow_table_cnt)。

    /*      

     * The rps_dev_flow_table structure contains a table of flow mappings.

     */ 

    struct rps_dev_flow_table {

            unsigned int mask;

            struct rcu_head rcu;

            struct rps_dev_flow flows[0];

    };

     rps_dev_flow类型的实例则主要包括存放着上次处理该流中报文的cpu以及所在cpu私有数据对象softnet_data的input_pkt_queue队列尾部索引的两个成员.

    /*

     * The rps_dev_flow structure contains the mapping of a flow to a CPU, the

     * tail pointer for that CPU's input queue at the time of last enqueue, and

     * a hardware filter index.

     */

    struct rps_dev_flow {

            u16 cpu;

            u16 filter;   

            unsigned int last_qtail;

    }; 

    下面的rps_sock_flow_table是一个全局的数据流表,这个表中包含了数据流期望被处理的CPU,是当前处理流中报文的应用程序所在的CPU。全局socket流表会在调recvmsg,sendmsg (inet_accept(), inet_recvmsg(), inet_sendmsg(), inet_sendpage() and tcp_splice_read())被设置更新。最终调用函数rps_record_sock_flow来更新ents数组的。

    mask成员存放的就是ents这个数组的大小,通过配置文件/proc/sys/net/core/rps_sock_flow_entries的方式指定的。

    rps_record_sock_flow函数定义在include/linux/netdevice.h文件中,

    每次用户程序读取数据包都会更新rps_sock_flow_table表,保证其中的CPU号是最新的

    /*

     * The rps_sock_flow_table contains mappings of flows to the last CPU

     * on which they were processed by the application (set in recvmsg).

     * Each entry is a 32bit value. Upper part is the high-order bits

     * of flow hash, lower part is CPU number.

     * rps_cpu_mask is used to partition the space, depending on number of

     * possible CPUs : rps_cpu_mask = roundup_pow_of_two(nr_cpu_ids) - 1

     * For example, if 64 CPUs are possible, rps_cpu_mask = 0x3f,

     * meaning we use 32-6=26 bits for the hash.

     */

    struct rps_sock_flow_table {      

            u32     mask;

     

            u32     ents[0] ____cacheline_aligned_in_smp;

    };

     

     

    1.1.3 RPS

      rps和rfs的工作都是在软中断上下文中执行,因为该阶段处理工作是和进程无关的,又和底层硬件剥离了。能够实现网络协议栈软中断的负载均衡。

      rps实现的总流程如下:将数据包加入其它CPU的接收队列,其它CPU将会在自己的软中断中执行process_backlog,process_backlog将会接收队列中的所有数据包,并调用__netif_receive_skb()执行后续工作。

    1.1.3.1  RPS配置

    Linux是通过配置文件的方式指定哪些cpu核参与到报文的分发处理,配置文件存放的路径是:/sys/class/net/(dev)/queues/rx-(n)/rps_cpus。

      设置好该配置文件之后,内核就会去获取该配置文件的内容,然后根据解析的结果生成一个用于参与报文分发处理的cpu列表,这样当收到报文之后,就可以建立起hash-cpu的映射关系了,解析函数为store_rps_map,结果存放在rps_map中。

    1.1.3.2  RPS细节

      rps会根据数据包的hash值(报文hash值,可以由网卡计算得到,也可以是由软件计算得到,具体的计算也因报文协议不同而有所差异,如tcp报文的hash值是根据四元组信息,即源ip、源端口、目的ip和目的端口进行hash计算得到的)来选择CPU,选目标cpu的动作具体的实现函数是get_rps_cpu,其定义在net/core/dev.c文件中, 实现从cpu列表中获取核号的:

    staticint get_rps_cpu(struct net_device *dev, struct sk_buff *skb, structrps_dev_flow **rflowp)

                rps是单纯用报文的hash值来分发报文,而不关注处理该流中报文的应用程序所在的cpu。

                那么何时调用函数get_rps_cpu呢?

                支持NAPI接口的驱动而言,在上半部主要就是将设备加入到cpu的私有数据softnet_data的待轮询设备列表中,下半部主要就是调用poll回调函数从网卡缓冲区中获取报文,然后向上给协议栈。

    函数get_rps_cpu会被netif_rcv_skb调用,获取到用于分发处理报文的目标cpu,如果目标cpu有效,则会调用enqueue_to_backlog()(net/core/dev.c  )函数,尝试将报文加入到cpu私有数据对象softnet_data的input_pkt_queue队列中。

    数据对象softnet_data中有backlog的成员,该成员类型为struct napi_struct,在函数enqueue_to_backlog()中,会将backlog加入到cpu的待轮询设备列表中,并触发软中断,在软中断处理函数net_rx_action()中会依次遍历待轮询设备列表中的设备,并调用设备注册的poll回调函数来进行报文处理。

    从input_pkt_queue队列该队列中取出报文,然后调用__netif_receive_skb()上报文送至协议栈进行后续处理。

    如果没有rps的处理流程(现在一般均采用的是NAPI收包方式),软中断处理函数net_rx_action()会调用网卡驱动注册的poll回调函数从网卡中获取到报文数据后就将报文数据上送至协议栈。

    对于有rps的处理流程,软中断处理函数net_rx_action()会调用网卡驱动注册的poll回调函数从网卡中获取到报文数据后,暂时不直接送至协议栈,而是选择一个目标cpu,将报文放到该cpu私有数据对象softnet_data的input_pkt_queue队列中,待对列input_pkt_queue满了之后,就将该cpu对应的backlog设备对象加入到该cpu的待轮询设备列表中,并触发软中断,软中断处理函数轮询到backlog设备对象后,调用poll回调函数process_backlog()从input_pkt_queue队列中取出报文,再上送至协议栈。

    如下图左边是没有使用rps,右边是使用rps。


    1.1.4 RFS

    RFS在RPS上的改进,通过RPS可以把同一流的数据包分发给同一个CPU核来处理,但是有可能发给该数据流分发的CPU核和执行处理该数据流的应用程序的CPU核不是同一个。

    当用户态处理报文的cpu和内核处理报文软中断的cpu不同的时候,就会导致cpu的缓存不命中。而rfs就是用来处理这种情况的,rfs的目标是通过指派处理报文的应用程序所在的cpu来在内核态处理报文,以此来增加cpu的缓存命中率。rfs和rps,主要差别就是在选取分发处理报文的目标cpu上。

    rfs实现指派处理报文的应用程序所在的cpu来在内核态处理报文主要是依靠两个流表来实现的:一个是设备流表rps_dev_flow_table,记录的是上次在内核态处理该流中报文的cpu;另外一个是全局的socket流表rps_sock_flow_table,记录报文期望被处理的目标cpu。

    1.1.4.1  RFS细节

    rfs相比于rps,主要差别就是在选取分发处理报文的目标cpu上。所以rfs负载均衡策略的实现也主要体现在函数get_rps_cpu()中,具体可以查看其中代码(et/core/dev.c)。

    rfs的负载均衡策略通过判断报文的hash值(流hash值)所对应的两个流表(设备流表和全局socket流表)中的记录的cpu是否相同来实施的。

    如果当前CPU表对应表项未设置或者当前CPU表对应表项映射的CPU核处于离线状态,那么使用期望CPU表对应表项映射的CPU核。

    如果当前CPU表对应表项映射的CPU核和期望CPU表对应表项映射的CPU核为同一个,就使用这一个核。

    如果当前CPU表对应表项映射的CPU核和期望CPU表对应表项映射的CPU核不为同一个:

    a)如果同一流的前一段数据包未处理完,必须使用当前CPU表对应表项映射的CPU核,避免乱序。

    b)如果同一流的前一段数据包已经处理完,那么则可以使用期望CPU表对应表项映射的CPU核。

     

    1.1.5 配置方法

    在大于等于2.6.35版本的Linux kernel上可以直接使用,默认都是关闭的。

    RPS设置:

    RPS指定哪些接收队列需要通过rps平均到配置的cpu列表上。

    /sys/class/net/(dev)/queues/rx-(n)/rps_cpus

    RFS设置:

    每个队列的数据流表总数可以通过下面的参数来设置:

    该值设置成rps_sock_flow_entries/N,其中N表示设备的接收队列数量。

    /sys/class/net/(dev)/queues/rx-(n)/rps_flow_cnt

    全局数据流表(rps_sock_flow_table)的总数,红帽是建议设置成32768,一般设置成最大并发链接数量

    /proc/sys/net/core/rps_sock_flow_entries

     

    1.1.6 参考

    Software receive packet steering

    RPS

    RFS

    RECEIVE FLOW STEERING (RFS)

    展开全文
  • linuxrps/rfs

    千次阅读 2010-12-22 22:21:00
    linux cpu 负载 平衡 rfs rps 网络

    最近看到一个用Linux内核的多队列收包与流控制技术RPS/RFS来平衡cpu负载的资料。当网络负载很重时,多cpu系统中,cpu0由于处理网卡中断,会导致cpu0负荷非常重。而其他cpu负荷相对要轻很多。此时,就可以用rps/rfs来平衡各个cpu的负载。具体还需要再仔细去查下资料。这里先mark一下。

     

    展开全文
  • Linux RPS/RFS 实现原理浅析

    万次阅读 2018-04-21 09:07:16
    本文快速解析一下RPS/RFS的基本原理。 RPS-Receive Packet Steering 下面这个就是RPS的原理: 其实就是一个软件对CPU负载重分发的机制。其使能的作用点在CPU开始处理软中断的开始,即下面的地方: netif_rx_...

    本文快速解析一下RPS/RFS的基本原理。

    RPS-Receive Packet Steering

    下面这个就是RPS的原理:
    这里写图片描述

    其实就是一个软件对CPU负载重分发的机制。其使能的作用点在CPU开始处理软中断的开始,即下面的地方:

    netif_rx_internal
    netif_receive_skb_internal

    RFS-Receive Flow Steering

    RFS在RPS的基础上,充分考虑到同一个五元组flow进程上下文和软中断上下文之间处理CPU的一致性,为此在socket层面也要有相应的处理。

      非常遗憾的是,一张图无法把这一切全部表达,那么我们分阶段进行,首先看同一个五元组flow第一个包到达的情形:
    这里写图片描述

    显然,global mapping作为全局映射,空间必须足够大才能容纳足够多的流,不然会相互覆盖。我建议设置成最大并发连接数的2倍。

      然后,当同一个flow的后续包到来时,我们看一下global mapping如何起作用。先来看后续第一个包到来时的情景:

    这里写图片描述

    仔细看图,这里增加了一个Per Queue Hash map,这些map是从global map生成的,此后的数据包再到达时,就可以查这个map了:

    这里写图片描述

    然而,这并没有看出来RFS和RPS的不同。

      你能保证处理softirq和处理socket的是同一个CPU吗?你不能,有可能tcp_v4_rcv是CPU0在处理,然后在data_ready中把socket进程唤醒,然而调度器将进程wakeup到CPU1上了,这样在update global hash map的时候,就会更新一个不同的CPU,这个时候RFS的作用就体现了,RFS会把Per Queue Hash Map也更新了,进而接下来的数据包会全部重定向到新的CPU上,然而RPS并不会这么做。

      RFS也不是只要发现CPU变了就无条件切换,而是要满足一个条件,即:
    同一个流上次enqueue到旧CPU的数据包全部被处理完毕
    如此可以保证同一个流处理的串行性,同时处理协议头的时候还能充分利用Hot cacheline。

    Accelerated RFS

    基本就是可以把软件发现的配置反向注入到硬件,需要硬件支持,不多说。


    本文只讲原理,想知道Howto,请参考内核源码包Documentation/networking/scaling.txt文件。


    trick and tips

    有时候太均匀太平等了并不是好事。

      在CPU运行繁重的用户态业务逻辑的时候,把中断打到同一个CPU上反而有一个天然限流的作用,要注意,先要找到瓶颈在哪里。如果瓶颈在业务逻辑的处理,那么当你启用RPS/RFS之后,你会发现用户态服务指标毫无起色,同时发现softirq飙高,这并不是一件好事。

      参考下面的图示:
    这里写图片描述

    这样好吗?为了所谓内核态处理的优雅均衡,挤压了用户态的CPU时间,这是典型的初学者行为,为了内核而优化内核,典型的物业殴打业主!

      其实,OS内核的作用只有一个,就是服务用户态业务逻辑的处理!

      不多说。

    展开全文
  • Linux系统中RPS/RFS介绍

    2017-02-23 16:12:53
    1 RPS/RFS ...RPS/RFS 功能是在Linux- 2.6.35中有google的工程师提交的两个补丁,这两个补丁的出现主要是基于以下两点现实的考虑: (1) 这两个补丁的出现,是由于服务器的CPU越来越强劲,可以到
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
  • LINUX---RPS/RFS转载

    2016-05-15 14:12:46
    【网络】Receive packet steering简称RPS (2014-07-02 14:06:34) 标签: 软中断 数据包 负载均衡 函数 cpu核心 分类: 网络相关 Linux 2.6.35于2010年8月1号发布,新增特性...
  • linux kernel 关于RSS/RPS/RFS/XPS的介绍

    千次阅读 2014-06-27 11:16:59
    原文链接... Scaling in the Linux Networking Stack Introduction ============ This document describes a set of complementary techniques in the
  • linux RFS

    千次阅读 2014-11-20 09:32:09
    如何充分利用多核优势来进行并行处理提高网络处理速度就是RPS解决的课题。以一个具有8核CPU和一个NIC的,连接在网络中的主机来说,对于由该主机产生并通过NIC发送到网络中的数据,CPU核的并行性是自热而然的事情: ...
  • 为什么80%的码农都做不了架构师?>>> ...
  • RFS特性

    2020-01-04 12:03:15
    数据包到达L4后会放入接收buffer中等待应用程序读取,如果能够更近一步,接收数据包的CPU和应用程序读取数据的CPU是同一个,那么就可以更好的提高cache命中率,进而能有更高的接收速率,这就是RFS补丁要做的事情。...
1 2 3 4 5 ... 15
收藏数 297
精华内容 118
关键字:

linux rfs rps