多队列网卡及RPS/RFS/XPS设置

本文转自:https://blog.csdn.net/u010039418/article/details/102828441

1、关于多队列网卡

通过lspci方式查看网卡信息,如果有MSI-X, Enable+ 并且Count > 1,则该网卡是多队列网卡,多队列网卡内部会有多个 Ring Buffer。

[root@localhost ~]# lspci -vvv | grep -A50 "Ethernet controller" | grep -E "Capabilities|Ethernet controller"
01:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)
	Capabilities: [40] Power Management version 3
	Capabilities: [50] MSI: Enable- Count=1/1 Maskable+ 64bit+
	Capabilities: [70] MSI-X: Enable+ Count=10 Masked-
	Capabilities: [a0] Express (v2) Endpoint, MSI 00
	Capabilities: [e0] Vital Product Data

从以上信息可见,我们的这张网卡是支持多队列的。

2、网卡支持最大队列数及当前使用队列

我们可以通过ethtool命令查看网卡支持的最大队列数,

[root@localhost ~]# ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:		0
TX:		0
Other:		1
Combined:	63
Current hardware settings:
RX:		0
TX:		0
Other:		1
Combined:	40

由上可见,该网卡最多支持63个队列,当前使用了40个队列。为什么不开启63个队列呢,因为机器的CPU数没那么多,

[root@localhost ~]# cat /proc/cpuinfo | grep processor | wc -l
40

我们开启多队列的初衷就是为了利用多核。队列数和CPU相等,正好可以每个CPU处理一个队列,这样效率比较高。

3、修改网卡队列数

有时候网卡支持多队列却没有开启,那么就要手动设置网卡队列数,

ethtool -L eth0 combined 8

其中combined指的是网卡收发队列共用的情况,有些网卡可单独设置收发队列,

ethtool -L eth0 rx 8
ethtool -L eth0 tx 8

设置后可以在/sys/class/net/eth0/queues/目录下看到对应的队列,

[root@localhost ~]# cd /sys/class/net/eth0/queues/
[root@localhost queues]# ls
rx-0  rx-2  rx-4  rx-6  tx-0  tx-2  tx-4  tx-6
rx-1  rx-3  rx-5  rx-7  tx-1  tx-3  tx-5  tx-7

4、多队列网卡绑核

为了保证CPU均衡,也即是网卡中断能分配到各个CPU,我们通常会将网卡中断绑核,具体操作见——网卡中断均衡设置

5、单队列网卡

上面说的都是多队列网卡,那单队列的怎么搞呢,不能厚此薄彼吧。这时候就出现RPS和RFS了。简单来说就是在软件层面模拟多队列的情况,从而达到CPU均衡。

RPS(Receive Packet Steering)把软中断的负载均衡到各个cpu,是在单个CPU将数据从Ring Buffer取出来之后开始工作,网卡驱动通过四元组(SIP,SPORT,DIP,DPORT)生成一个hash值,然后根据这个hash值分配到对应的CPU上处理,从而发挥多核的能力。

但是还有个问题,由于RPS只是把数据包均衡到不同的cpu,但是收包的应用程序和软中断处理不一定是在同一个CPU,这样对于cpu cache的影响会很大。因此就出现RFS(Receive flow steering),它确保应用程序和软中断处理的cpu是同一个,从而能充分利用cpu的cache,这两个补丁往往都是一起设置,以达到最好的优化效果。

6、设置RPS

首先内核要开启CONFIG_RPS编译选项,然后设置需要将中断分配到哪些CPU,

 /sys/class/net/<dev>/queues/rx-<n>/rps_cpus

比如,要将eth0上0号收包软中断均匀分配到64个CPU上(假设机器上有这么多CPU),那么可以如下操作,

 echo "ffffffff,ffffffff" > /sys/class/net/eth0/queues/rx-0/rps_cpus

和多队列中断绑定规则类似,每个CPU用1位表示,因此1,2,4,8分别对应0-3号CPU,分配到这些CPU,相加就是15,即f。

如果只想分配到前32个CPU,则可以如下操作,

 echo "00000000,ffffffff" > /sys/class/net/eth0/queues/rx-0/rps_cpus

7、设置RFS

上面我们说过RPS和RFS一般要配合使用,效果才最优,因此RFS同样需要开启CONFIG_RPS编译选项,同时设置每个队列的数据流表总数才能真正生效。

这里我们了解一下RFS的细节:
**RFS的实现需要依赖两个表——全局socket流表(rps_sock_flow_table)和设备流表(rps_dev_flow_table)。**全局socket流表记录的是每个流由上面RPS计算通过hash分配的CPU号,也就是期望的CPU号;设备流表存在于每个网络设备的每个接收队列,表中记录的是每个未完成流使用的CPU号,也就是当前流使用的CPU号。具体使用哪个CPU简单来说有以下规则,

如果两个表中记录的对应流使用的是同一个CPU号,就使用这个CPU
如果当前流使用的CPU未设置或者CPU处于离线状态,那就使用期望CPU表中的CPU号,也就是RPS计算而得的CPU号
如果两个表中对应流记录的CPU核不是同一个:
a)如果同一流的前一段数据包未处理完,为了避免乱序,不更换CPU,继续使用当前流使用的CPU号
b)如果同一流的前一段数据包已经处理完,那就可以使用期望CPU表中的CPU号
因此我们需要设置这两个表中记录的entry,对于全局socket流表(rps_sock_flow_table),该配置接口是

/proc/sys/net/core/rps_sock_flow_entries

而设备流表(rps_dev_flow_table)则通过以下接口设置,

/sys/class/net/<dev>/queues/rx-<n>/rps_flow_cnt

两者的关系如下,

rps_sock_flow_entries = rps_flow_cnt * N

其中,N就是队列数量。因此,对于单队列网卡,两个值是一样的。

8、XPS(Transmit Packet Steering)

上面说的都是关于接收队列,那对于发送队列呢,这就需要用到XPS了。

XPS通过创建CPU到网卡发送队列的对应关系,来保证处理发送软中断请求的CPU和向外发送数据包的CPU是同一个CPU,用来保证发送数据包时候的局部性。

对于发送队列到CPU的映射有两种选择:

1、使用CPU映射
这种方式是通过指定发送队列在某几个CPU上处理,通过减小分发的CPU范围来减少锁开销以及cache miss。最常见的就是1对1,和上面说到的接收软中断绑核类似,通过以下接口设置,

/sys/class/net/<dev>/queues/tx-<n>/xps_cpus

同样是bitmaps方式。

2、接收队列映射方式
这种方式基于接收队列的映射来选择CPU,也就是说让接收队列和发送队列在同一个CPU,或指定范围的几个CPU来处理。这种方式对于多线程一直收发包的系统效果比较明显,收发包队列处理在同一个CPU,不仅减少了对其他CPU的打断,同时提高应用处理效率,收完包后直接在同个CPU继续发包,从而减小CPU消耗,同时减小包的时延。

这种方式映射,可通过一下接口设置(不是所有网卡都支持),

/sys/class/net/<dev>/queues/tx-<n>/xps_rxqs

另外,XPS对于单发送队列网卡没有效果,这个可想而知。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值