网卡优化

大量小包的CPU密集型系统调优案例一则

http://blog.netzhou.net/?p=181

我的blog前面有一篇文章描述了软终端导致单cpu消耗100%,导致机器丢包跟延迟高的问题,文中我只是简单的说明了一下升级内核进行解决的,这个问题我并没有进行一个问题解决的说明,经历了一系列的调整后,单机的并发从单机单网卡承受100M流量到160M流量,到现在的最高的230M流量,在程序没有大规模修改的情况下效果还是十分的明显,这次这篇文章将完整的说一下我的一个解决方法:
先说说我的场景,我目前负责的一个项目,大量的小数据包,长连接,每个数据包都不大,大概10Kbit左右一个包,但是数量十分之大,目前在生产环境中最大的数据包数量高达15W/s的数量,常见的网游系统,小图片cdn系统,这些服务类型都算是这种类型,单网卡流量不大,但是数据包数量极大,我目前调优的结果是
在Xeon E5504, BCM5716的网卡,8G的dell r410的机器,单网卡实现了230MBits大的流量,系统的load为0,8颗cpu每一颗还有10%左右的IDLE,由于我们的系统是数据包的转发,还有一个网卡同期的流量使220M,12.8W的数据包,算上总数,大概可以到450MBits的流量,25.5W的小包,由于人数有限,流量没有跑上去,预计可以跑到480MBits的流量,生产环境的一台机器的数据:
流量及机器的网卡包数量

机器的cpu消耗

首先机器的选型,由于大量小包的cpu密集的系统,当然cpu越性能越高越好咯,但是成本相应的高。对于这种类型的机器,网卡选型也是十分的重要,一定要选择支持msi-x的网卡类型,什么是msi-x大家可以查询google资料去了解一下,目前市面出售的大部分最新的网卡都有这个功能,查看方法lspci -v,看到如下图的内容

再者网卡是否支持多队列,多队列网卡十分的重要,不是多队列的网卡,这篇文章几乎不需要看了,可以直接忽略掉,查看方法cat /proc/interrupts,这个方法并不适用所有的操作系统例如在rhel 5.5的os当中,bcm5716的网卡就看不到,具体我也没有查到怎么查看的方法,麻烦知道的用户告知一声,如果是的话应该可以看到如下图的内容

每一个网卡有8个队列,对于这种大量小包的cpu密集型的系统,多队列的网卡性能至少提供性能50%以上,我们生产环境的有台非多队列的Intel 82574的网卡调优后只能跑到160M左右流量,跟上图明显的一个对比.而同等情况下买一个多队列的网卡明显要便宜很多。
操作系统的选择,目前大部分企业使用的是rhel系列的os,包括标准的rhel跟centos作为一个生产环境的os,目前主力的版本还是rhel 5系列的os,而rhel 5系列的内核版本对于软中断处理并不是很好,调优的结果不是很理想,在rhel 5系列的os上,我们最高流量单网卡也就是160M左右,而且机器的load也很高了,机器已经出现小量的丢包,而且只是使用了4到6个cpu还有几个cpu没有利用上,机器性能没有挖掘完毕,由于我们的机器没有存储的压力,单纯的只是消耗cpu资源,没有io的压力,于是大胆的启用刚出的rhel 6.1的系统,看重这个系统的原因是,该os的内核已经加入了google的两个原本在2.6.35当中才启用的2个补丁——RPS/RFS,RPS主要是把软中断的负载均衡到各个cpu,由于RPS只是单纯把数据包均衡到不同的cpu,这个时候如果应用程序所在的cpu和软中断处理的cpu不是同一个,此时对于cpu cache的影响会很大,那么RFS确保应用程序处理的cpu跟软中断处理的cpu是同一个,这样就充分利用cpu的cache,默认情况下,这个功能并没有开启,需要手动开启开启方法,开启的前提是多队列网卡才有效果。
echo ff > /sys/class/net/<interface>/queues/rx-<number>/rps_cpus
echo 4096 > /sys/class/net/<interface>/queues/rx-<number>/rps_flow_cnt
echo 30976 > /proc/sys/net/core/rps_sock_flow_entries
对于2个物理cpu,8核的机器为ff,具体计算方法是第一颗cpu是00000001,第二个cpu是00000010,第3个cpu是00000100,依次类推,由于是所有的cpu都负担,所以所有的cpu数值相加,得到的数值为11111111,十六进制就刚好是ff。而对于/proc/sys/net/core/rps_sock_flow_entries的数值是根据你的网卡多少个通道,计算得出的数据,例如你是8通道的网卡,那么1个网卡,每个通道设置4096的数值,8*4096就是/proc/sys/net/core/rps_sock_flow_entries的数值,对于内存大的机器可以适当调大rps_flow_cnt,这个时候基本可以把软中断均衡到各个cpu上了,而对于cpu的使用,还有其它的例如use,sys等,这个不均衡的话,cpu还是会浪费掉,同时对我们的程序针对多cpu进行小部分的开发跟重新编译,本身我们程序就是多进程的一个模型,我们采用nginx的进程管理模型,一个master管理work进程,master分配每一个连接给work进程,由work进程处理用户的请求,这样每一个进程都能均衡负担几乎相同的处理请求,同时在6.1的系统中gcc新增一个openmp的指令,这个指令作用针对多核,增加程序的并行计算的功能,不需要大规模的更改代码就能实现多核的并行性计算,具体使用使用方法请见如下url

http://zh.wikipedia.org/zh/OpenMP

针对上面的处理,基本上可以实现cpu按理说可以实现完全的均衡了,但是当我们在实际的使用过程中发现还是cpu还不是100%的均衡,存在1到2个cpu消耗量还是比其它的要大20%左右,导致在高峰期有1到2个cpu的idle使用完毕,导致用户使用存在卡的情况,这个时候,需要手动调节一下cpu的使用情况,在这操作之前先了解几个名词以及其作用
一个是IO-APIC(输入输出装置的高级可编程中断控制器)
为了充分挖掘 SMP 体系结构的并行性,能够把中断传递给系统中的每个CPU至关重要,基于此理由,Intel 引入了一种名为 I/O-APIC的东西。该组件包含两大组成部分:一是“本地 APIC”,主要负责传递中断信号到指定的处理器;举例来说,一台具有三个处理器的机器,则它必须相对的要有三个本地 APIC。另外一个重要的部分是 I/O APIC,主要是收集来自 I/O 装置的 Interrupt 信号且在当那些装置需要中断时发送信号到本地 APIC。这样就能充分利用多cpu的并行性。如果用户对于IO-APIC更感兴趣,请见如下url的中的pdf的说明

http://wenku.baidu.com/view/ccdc114e2e3f5727a5e962e9.html

另外一个就是irqbalance
irqbalance 用于优化中断分配,它会自动收集系统数据以分析使用模式,并依据系统负载状况将工作状态置于 Performance mode 或 Power-save mode.处于 Performance mode时irqbalance 会将中断尽可能均匀地分发给各个CPU以充分利用 CPU 多核,提升性能.处于 Power-save mode时,irqbalance 会将中断集中分配给第一个 CPU,以保证其它空闲 CPU 的睡眠时间,降低能耗
通过这我们就发现我们是一个非常繁重的系统,并没有节能的需求,而是需要充分利用各个cpu的性能,而事实上在一个大量小包的系统上,irqbalance优化几乎没有效果,而且还使得cpu消耗不均衡,导致机器性能得不到充分的利用,这个时候需要把它给结束掉
/etc/init.d/irqbalance stop
同时,手动绑定软中断到指定的cpu,对于一个8个队列的网卡,8核的机器,可以指定一个cpu处理一个网卡队列的中断请求,并根据cpu的消耗情况,手动调整单个网卡的队列到资源消耗低的cpu上,实现手动均衡,具体操作方法,执行如下命令
cat /proc/interrupts

计算cpu的方法第一颗为00000001换算成16进制为1,第2颗cpu为00000010换算成16进制为2,依次类推得出,第8颗cpu为80,这样就可以做如下的绑定了
echo 0001 > /proc/irq/<number>/smp_affinity
这样就可以绑定中断到指定的cpu了,这个时候有可能会问,我的机器是一个2通道的网卡,这个时候如果一个通道一个cpu绑定,这个时候就浪费了6颗cpu了,还是达不到完全均衡负载,为什么不能像前面rps那样,
echo ff > /proc/irq/<number>/smp_affinity
设置一个ff达到所有的cpu一起均衡呢,这个因为io-apic工作的2个模式logical/low priority跟fixed/physical模式,这两个模式的区别在于,前面一个模式能够把网卡中断传递给多核cpu进行处理,后一种模式对应一个网卡队列的中断只能传递给单cpu进行处理,而linux是fixed/physical工作模式,如果你设置上面那个选项,只能第一个cpu进行软中断的处理,又回到未优化前了。那么为什么不开启logical/low priority呢,当一个tcp连接发起,当数据包到底网卡,网卡触发中断,中断请求到其中一个cpu,而logical/lowpriority并不能保证后续的数据包跟前面的包处于同一个cpu,这样后面的数据包发过来,又可能处于另外一个cpu,这个时候同一个socket都得检查自己的cpu的cache,这样就有可能部分cpu取不到数据,因为本身它的cache并没用数据,这个时候就多了多次的cpu的查找,不能充分利用cpu的效率。对于部分机器来说并不能开启logical/low priority模式,一种可能是cpu过多,另外一种是bios不支持。因此对于那种单队列网卡并不能充分发挥cpu的性能。
经过上述的调整基本可以达到几乎完全均衡的效果,每个cpu都能发挥他的效果。也几乎可以到达我调优的效果
对于一个完整的系统来说,不仅有数据包发送的需求还有数据接收的请求,而rps/rfs主要解决数据接收的一个中断均衡的问题,rps/rfs的作者提交了一个xps(Transmit Packet Steering), 这个patch主要是针对多队列的网卡发送时的优化,当发送一个数据包的时候,它会根据cpu来选择对应的队列,目前这个patch已经添加在2.6.38内核版本当中,我们已经在生产环境中,部分机器上已经使用上了,据作者的benchmark,能够提高20%的性能,具体使用方法
echo ff > /sys/class/net/<interface>/queues/tx-<number>/xps_cpus
由于还是新上的系统,还没敢大规模放用户进来,还在测试系统的稳定性,不知道上限具体能到多少,从当前生产环境跑的流量来看,比同等其它的机器,cpu消耗情况,确实要减少一些,流量没有跑上来,效果不是特别的明显,还有待继续测试,得出一个具体的结果。
另外对于intel的网卡的用户,intel有个叫ioat的功能,关于ioat功能大家可以网上查查资料.
而对于centos的用户来说,目前还只是出了6.0的版本,并没有上述功能,要大规模的推广,建议大家编译2.6.38的内核版本,因为2.6.38的版本已经包含了上述几个补丁。编译内核生成内核的rpm包,能快速的在同一批机器上快速部署上去。
以上就是我的对cpu密集型系统的一个优化过程,欢迎大家来讨论。

多队列网卡简介

http://blog.csdn.net/turkeyzhou/article/details/7528182

多队列网卡是一种技术,最初是用来解决网络IO QoS (quality of service)问题的,后来随着网络IO的带宽的不断提升,单核CPU不能完全处满足网卡的需求,通过多队列网卡驱动的支持,将各个队列通过中断绑定到不同的核上,以满足网卡的需求。

常见的有Intel的82575、82576,Boardcom的57711等,下面以公司的服务器使用较多的Intel 82575网卡为例,分析一下多队列网卡的硬件的实现以及linux内核软件的支持。

1.多队列网卡硬件实现

图1.1是Intel 82575硬件逻辑图,有四个硬件队列。当收到报文时,通过hash包头的SIP、Sport、DIP、Dport四元组,将一条流总是收到相同的队列。同时触发与该队列绑定的中断。

图1.1 82575硬件逻辑图

2. 2.6.21以前网卡驱动实现

kernel从2.6.21之前不支持多队列特性,一个网卡只能申请一个中断号,因此同一个时刻只有一个核在处理网卡收到的包。如图2.1,协议栈通过NAPI轮询收取各个硬件queue中的报文到图2.2的net_device数据结构中,通过QDisc队列将报文发送到网卡。

图2.1 2.6.21之前内核协议栈

 


图2.2 2.6.21之前net_device

3. 2.6.21后网卡驱动实现

2.6.21开始支持多队列特性,当网卡驱动加载时,通过获取的网卡型号,得到网卡的硬件queue的数量,并结合CPU核的数量,最终通过Sum=Min(网卡queue,CPU core)得出所要激活的网卡queue数量(Sum),并申请Sum个中断号,分配给激活的各个queue。

如图3.1,当某个queue收到报文时,触发相应的中断,收到中断的核,将该任务加入到协议栈负责收包的该核的NET_RX_SOFTIRQ队列中(NET_RX_SOFTIRQ在每个核上都有一个实例),在NET_RX_SOFTIRQ中,调用NAPI的收包接口,将报文收到CPU中如图3.2的有多个netdev_queue的net_device数据结构中。

这样,CPU的各个核可以并发的收包,就不会应为一个核不能满足需求,导致网络IO性能下降。

图3.1 2.6.21之后内核协议栈

 

图3.2 2.6.21之后net_device

4.中断绑定

当CPU可以平行收包时,就会出现不同的核收取了同一个queue的报文,这就会产生报文乱序的问题,解决方法是将一个queue的中断绑定到唯一的一个核上去,从而避免了乱序问题。同时如果网络流量大的时候,可以将软中断均匀的分散到各个核上,避免CPU成为瓶颈。

 

 

图4.1 /proc/interrupts

5.中断亲合纠正

一些多队列网卡驱动实现的不是太好,在初始化后会出现图4.1中同一个队列的tx、rx中断绑定到不同核上的问题,这样数据在core0与core1之间流动,导致核间数据交互加大,cache命中率降低,降低了效率。


图5.1 不合理中断绑定

linux network子系统的负责人David Miller提供了一个脚本,首先检索/proc/interrupts文件中的信息,按照图4.1中eth0-rx-0($VEC)中的VEC得出中断MASK,并将MASK

写入中断号53对应的smp_affinity中。由于eth-rx-0与eth-tx-0的VEC相同,实现同一个queue的tx与rx中断绑定到一个核上,如图4.3所示。

                                                                                     




图4.2 set_irq_affinity

图4.3 合理的中断绑定

 

set_irq_affinity脚本位于http://mirror.oa.com/tlinux/tools/set_irq_affinity.sh。

6.多队列网卡识别

#lspci -vvv

Ethernet controller的条目内容,如果有MSI-X && Enable+ && TabSize > 1,则该网卡是多队列网卡,如图4.4所示。

图4.4 lspci内容

Message Signaled Interrupts(MSI)是PCI规范的一个实现,可以突破CPU 256条interrupt的限制,使每个设备具有多个中断线变成可能,多队列网卡驱动给每个queue申请了MSI。MSI-X是MSI数组,Enable+指使能,TabSize是数组大小。


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值