暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【日积月累】网卡多队列的理解

老张的技术博客 2018-04-04
3314

一、单队列的瓶颈

单队列的情形下,一个网卡一次只能申请一个中断号,因此同一个时刻只有一个核在处理网卡收到的数据包。如下图所示,协议栈通过NAPI轮询来收取各个硬件队列中的报文,并将其发送到net_device数据结构中,最后通过QDisc队列将报文发送到网卡。(相关数据结构在本文后面提到)


二、多队列网卡的实现

内核2.6.21以后才支持多队列模式。

我们来梳理下流程:

当网卡驱动加载时,它首先会去获得网卡的型号,并得到网卡硬件队列的数量(queue)。这个queue和cpu的核数通过一系列算法得到一个最小值(min),这个值就是所要激活网卡queue的数量。之后会申请min个中断号,分配给激活的各个queue。当某个queue收到报文之后就触发中断,这时,收到中断的核就会将其放到协议栈负责收包的NET_RX_SOFTIRQ队列中,在NET_RX_SOFTIRQ中会调用NAPI的收包接口。

这样就能充分利用各个核来进行收发包了。

上图:


三、报文乱序问题

由于cpu是平行收包的,可能会遇到一个问题:多个cpu核收到同一个queue的报文,这样就会产生报文乱序。无序是运维中一直要努力规避的现象。报文乱序问题的根源就是中断的无序现象。因此,要解决这个问题,只需将一个queue的中断绑定到唯一的一个核上去。这样一来,每个cpu都从规定的queue中收取报文,数据包就不会发生”撞车“了

四、中断亲和纠正问题

在实践中,还存在一个现象:同一个队列的收包(rx)和发包(tx),会被中断绑定到不同的核上。如下图所示,假设收包的动作在0号核上,发包的动作却在3号核上,这样当数据包到达0号核还得传输到3好核来进行发送。在发送包核内的本地缓存中找不到相应的数据,cache命中率就降低,也就降低了效率。


要解决这个问题,可以利用smp_affinity来实现。大牛David Miller提供了一个脚本,它的实现方法是首先检索/proc/interrupts文件,来获取终端号。然后在smp_affinity里面定义中断要在哪个cpu核上进行。部分代码如下


由此就可以在收发包于同一核了,如下图


五、识别网卡多队列

一个主机能否支持多队列取决于kernel网络子系统、网卡驱动、网卡硬件自身。这些条件都必须得满足,缺一不可

我收集了两种方法:

1、cat  /proc/interrupts

以此来观察是否存在多个网卡的终端号

2、ethtool  -S  eth0

六、开启网卡多队列

要开启网卡多队列首先要进行系统层和硬件层的检查

之后可用ethtool来开启多队列模式

ethtool -S eth0 #查看队列个数 ethtool -L eth0 combined <N> # 配置队列个数.


文章转载自老张的技术博客,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论