网卡多队列

本篇博文介绍一些有关网卡多队列的内容,该文为 zstack 培训 - 性能分析课程笔记 1 的扩展阅读。

网卡多队列源自于网络 QoS 问题,网络 QoS 问题提出的队列模型,对 I/O 的开发以及网络性能的调优具有很大的指导意义。

第一节的网络 QoS 给出原理及算法的指导;

第二节讲诉在驱动和内核中是如何调度这些队列的。

1、网络 QoS1

该部分内容摘取自 http://www.h3c.com/cn/d_201104/713021_97665_0.htm

在看网卡多队列之前,我们先来看看 QoS(Quality of Service)。QoS 即服务质量,网络的 QoS 包含很多个方面的内容,例如:带宽、时延、丢包率等。为了提高 QoS,工程师们提出了一些行之有效的 QoS 模型。

网络中的通信由各种不同的应用流组成,这些应用对网络服务和性能的质量有不同的要求,例如:FTP 下载业务希望获取更多的带宽,VoIP 语音业务则希望减少延迟和抖动。根据网络对应用的控制能力的不同,可以将网络分为不同的 QoS 模型。

  1. Best Effort 模型(尽力而为),这是最简单的模型,应用程序可以在任何时候,发出任意数量的报文,网络尽最大的可能性来发送报文,对带宽、时延、抖动和可靠性等不提供任何保证。

    它是 Internet 的缺省服务模型,通过单独的 FIFO 实现;

  2. DiffServ 模型(区分服务),由 RFC2475 定义,在区分服务中,根据服务要求对不同业务的数据进行分类,对报文按类进行优先级标记,然后有差别地提供服务。

    区分服务一般用来为一些重要的应用提供端到端的 QoS,它通过下列技术来实现:

    1)流量标记与控制技术:它根据报文的 CoS(Class of Service,服务等级)域、ToS 域(对于 IP 报文是指 IP 优先级或者 DSCP)、IP 报文的五元组(协议、源地址、目的地址、源端口号、目的端口号)等信息进行报文分类,完成报文的标记和流量监管。目前实现流量监管技术多采用令牌桶机制。

    2)拥塞管理与拥塞避免技术:WRED、PQ、CQ、WFQ、CBQ 等队列技术对拥塞的报文进行缓存和调度,实现拥塞管理与拥塞避免。

  3. IntServ 模型,由 RFC1633 定义,在这种模型中,节点在发送报文前,需要向网络申请资源预留,确保网络能够满足数据流的特定服务要求。

    IntServ 可以提供保证服务和负载控制服务两种服务,保证服务提供保证的延迟和带宽来满足应用程序的要求;负载控制服务保证即使在网络过载的情况下,也能对报文提供与网络未过载时类似的服务。

1.1、FIFO 队列

FIFO 队列不对报文进行分类,当报文进入接口的速度大于接口能发送的速度时,FIFO 按报文到达接口的先后顺序让报文进入队列,同时,FIFO 在队列的出口让报文按进队的顺序出队,先进的报文将先出队,后进的报文将后出队。

FIFO 队列具有处理简单,开销小的优点。但 FIFO 不区分报文类型,采用尽力而为的转发模式,使对时间敏感的实时应用(如 VOIP)的延迟得不到保证,关键业务的带宽也不能得到保证。

1.2、PQ 原理

PQ(Priority Queuing)需要网卡提供多队列支持,它将消息按照优先级分为四个队列,并且总是优先发送更高优先级队列的报文,这样做同样也会产生一些问题,比如,当高优先级队列总有报文时会导致低优先级“饿死”。PQ 队列的特性使其能够保证实时业务的优先处理,对 VoIP 业务有较好的优化。

PQ 队列根据网络协议、数据流入接口、报文长短、IP 报文的 ToS、五元组(协议 ID、源 IP、目的 IP、源端口、目的端口)等条件来对数据报文进行分类。最多分为 4 类。

1.3、CQ 原理

CQ(Custom Queuing)同样需要网卡提供多队列支持,它的原理与 PQ 相似,不同在于,它能够将报文最多分至 17 类,每类报文对应 CQ 中的一个队列,接口拥塞时,报文按匹配规则被送入对应的队列;如果报文不匹配任何规则,则被送入缺省队列(缺省队列默认为 1,可配置修改缺省队列)。

CQ 的 17 个队列中,0 号队列为系统队列,它的优先级是最高的,总是要保证 0 号队列中的报文呗发送完。剩余的 1 到 16 号队列采用轮询方式,根据用户配置的额度依次取一定数量的报文发送,若轮到为空,则轮到下一队列。

CQ 把报文分类,然后按类别将报文分配到 CQ 的一个队列中去,而对每个队列,又可以规定队列中的报文所占接口带宽的比例,这样,就可以让不同业务的报文获得合理的带宽,从而既保证关键业务能获得较多的带宽,又不至于使非关键业务得不到带宽。但由于采用轮询调度各个队列,CQ 无法保证任何数据流的延迟。

1.4、WFQ 原理

WFQ(Weighted Fair Queuing),加权平均队列。WFQ 对报文按流特征进行分类,对于 IP 网络,相同源 IP 地址、目的 IP 地址、源端口号、目的端口号、协议号、ToS 的报文属于同一个流,而对于 MPLS 网络,具有相同的标签和 EXP 域值的报文属于同一个流。每一个流被分配到一个队列,该过程称为散列,采用 HASH 算法来自动完成,这种方式会尽量将不同特征的流分入不同的队列中。每个队列类别可以看作是一类流,其报文进入 WFQ 中的同一个队列。WFQ 允许的队列数目是有限的,用户可以根据需要配置该值。

在出队的时候,WFQ 按流的优先级(precedence)来分配每个流应占有出口的带宽。优先级的数值越小,所得的带宽越少。优先级的数值越大,所得的带宽越多。这样就保证了相同优先级业务之间的公平,体现了不同优先级业务之间的权值。

WFQ 优点在于配置简单,有利于小包的转发,每条流都可以获得公平调度,同时照顾高优先级报文的利益。但由于流是自动分类,无法手工干预,故缺乏一定的灵活性,且受资源限制,当多个流进入同一个队列时无法提供精确服务,无法保证每个流获得的实际资源量。WFQ 均衡各个流的延迟与抖动,同样也不适合延迟敏感的业务应用。

1.5、CBQ 原理

CBQ(Class Based Queuing)基于类的队列。CBQ 首先根据 IP 优先级或者 DSCP、输入接口、IP 报文的五元组等规则来对报文进行分类;对于 MPLS 网络的 LSR,主要是根据 EXP 域值进行分类。然后让不同类别的报文进入不同的队列。对于不匹配任何类别的报文,报文被送入系统定义的缺省类。

CBQ 包括一个低时延队列 LLQ(Low Latency Queuing,低时延队列),用来支撑 EF(Expedited Forwarding,快速转发)类业务,被绝对优先发送,保证时延。进入 EF 的报文在接口没有发生拥塞的时候(此时所有队列中都没有报文),所有属于 EF 的报文都可以被发送。在接口发生拥塞的时候(队列中有报文时),进入 EF 的报文被限速,超出规定流量的报文将被丢弃。

另外有 64 个 BQ 队列(Bandwidth Queuing,带宽保证队列),用来支撑 AF(Assured Forwarding,确保转发)类业务,可以保证每一个队列的带宽及可控的时延。系统调度报文出队列的时候,按用户为各类报文设定的带宽将报文出队发送。这种队列技术应用了先进的队列调度算法,可以实现各个类的队列的公平调度。当接口中某些类别的队列没有报文时,BQ 队列的报文还可以公平地得到空闲的带宽,和时分复用系统相比,大大提高了线路的利用率。同时,在接口拥塞的时候,仍然能保证各类报文得到用户设定的最小带宽。

最后还有一个 WFQ 队列,对应 BE(Best Effort,尽力传送)业务,使用接口剩余带宽进行发送。

CBQ 可根据报文的输入接口、满足 ACL 情况、IP Precedence、DSCP、EXP、Label 等规则对报文进行分类、进入相应队列。对于进入 EF 和 AF 的报文,要进行测量;考虑到链路层控制报文的发送、链路层封装开销及物理层开销(如 ATM 信元头),建议 EF 与 AF 占用接口的总带宽不要超过接口带宽的 75%。

CBQ 可为不同的业务定义不同的调度策略(如带宽、时延等),由于涉及到复杂的流分类,对于高速接口(GE 以上)启用 CBQ 特性系统资源存在一定的开销。

1.6 RTP 原理

RTP 优先队列 (Real Time Protocol Priority Queuing) 。

RTP 优先队列是一种保证实时业务(包括语音与视频业务)服务质量的简单队列技术。其原理就是将承载语音或视频的 RTP 报文送入高优先级队列,使其得到优先发送,保证时延和抖动降低为最低限度,从而保证了语音或视频这种对时延敏感业务的服务质量。

RTP 优先队列将 RTP 报文送入一个具有较高优先级的队列,RTP 报文是端口号在一定范围内为偶数的 UDP 报文,端口号的范围可以配置,一般为 16384~32767。RTP 优先队列可以同前面所述的任何一种队列(包括 FIFO、PQ、CQ、WFQ 与 CBQ)结合使用,它的优先级是最高的。由于 CBQ 中的 EF 完全可以解决实时业务,所以不推荐将 RTP 优先队列与 CBQ 结合应用。

由于对进入 RTP 优先队列的报文进行了限速,超出规定流量的报文将被丢弃,这样在接口拥塞的情况下,可以保证属于 RTP 优先队列的报文不会占用超出规定的带宽,保护了其他报文的应得带宽,解决了 PQ 的高优先级队列的流量可能“饿死”低优先级流量的问题。

2、多核 CPU,网卡多队列

1 中所介绍的不同多队列调度方式,本质上还是在对网卡带宽进行分配调度,这对于单个 CPU 来说情况并没有任何改变(单核 CPU:所有的苦都是我一个人承担)。

随着网络 IO 的带宽不断提升(万兆网卡,多个万兆网卡。。),单核 CPU 已经无法满足网卡的需求了。这时候就需要多个 CPU 一起来处理网卡的多个队列。

2.1、网卡驱动的支持

2.6.21 版本后 Kernel 支持网卡多队列特性,当网卡驱动加载时,驱动判断当前网卡型号,得知网卡硬件 FIFO 的数量,再结合 CPU 核数,最终通过Sum = Min得出要激活的网卡 queue 数量,同时申请同样数量的中断,再通过中断亲和给不同的 CPU 核分配不同的 FIFO。

当某个 FIFO 收到报文时,出发相应的中断,收到中断的 CPU 执行中断服务程序,获取该 FIFO 上的数据报文。需要注意的是,在设置中断亲和性的时候最好将不同的 FIFO 分配给不同的 CPU 核,这样才能使得并发效率最佳,同时同一 FIFO 的 tx 和 rx 中断最好绑定到一起。

这样 CPU 的各个核就可以并发地收发数据报文。

2.2、识别多队列网卡

通过 lspci 命令可以看到物理网卡上的 FIFO 数量

1
$ lspci -vvv

若出现MSI-X:Enable+ Count值 > 1,那么该网卡为多队列网卡。多队列网卡驱动给每个 queue 申请了 MSI。MSI-X 是 MSI 数组,Enable+ 指使能,TabSize 是数组大小。

通过 ethtool 命令课设置网卡队列

1
2
$ ethtool -l eth0 #查看 eth0 网卡 channel 状态
$ ethtool -L eth0 combined 4 #将网卡队列数设置为 4

# 4、参考

  1. QoS 的基本原理:http://www.h3c.com/cn/d_201104/713021_97665_0.htm