最近用linux做nat多出口时,遇到的几个问题,经过一个星期的资料查找跟具体实践终于给解决了,由于的问题复杂性,加之个人水平十分有限,解决的过程十分的痛苦,为了使更多的人,不痛苦或者少痛苦一点,介绍一下问题解决的过程。
先说说环境
1.硬件:DELL R410
2.网卡:板载1000M BCM5709
2.OS: RHEL 5.5 x86_64
3.KERNEL: 2.6.18-194.el5
所出现的问题
1.网卡毫无征兆的down掉,而且没有任何log信息
2.当流量增大时,不到理论上限的1/3时机器出现网络延迟严重,伴随大量的丢包
3.机器的cpu软中断不均衡,只有1个cpu处理软中断,并且该cpu的软中断周期性的达到100%
4.内外网网卡做nat丢包数据量不一致,差别很大,不在同一个数量级
想必第一个问题,大部分使用bcm网卡,rhel 5.3以后得机器都会遇到这种情况,网上的资料比较的多,我也不多啰嗦了,直接升级网卡驱动就可以解决了。第二,三,四其实是同一个问题都是由于网卡中断过多,cpu处理不过来(准确的说,cpu分配不均衡,导致只有一个cpu处理,处理不过来),引起丢包,那么为什么两个网卡丢包的数量级不一样呢,下面从原理上进行解释,既然是做nat多出口,那么就有大量的路由信息,是一个网络应用,当一个数据包请求nat时,数据包先被网卡驱动的数据接收,网卡收到数据时,触发中断。在中断执行例程中,把skb挂入输入队列,并触发软中断。稍后的某个时刻,当软中断执行时,再从该队列中把skb取下来,投递给上层协议。
如果在这个过程当中cpu没有及时处理完这个队列导致网卡的buffer满了,网卡将直接丢弃该数据包。这里牵涉到2个队列,一个是tx,一个是rx,它的队列的大小默认都是255,可以通过ethtool -g eth0(你指定的网卡),为了防止丢包,当时我通过ethtool -G eth0 rx xxx 把它调大了,但是调大以后,还是杯水车薪啊,通过ethtool -S eth0 |grep rx_fw_discards,发现数值还是不停的在增长,也就是说还在不停的丢包,cpu处理不过来,这时候找到网上有人在利用lvs时也遇到这个问题,cpu软中断分配不均衡,只有一个cpu处理软中断的问题,网上的资料五花八门,有建议使用修改设备中断方式。即通过修改设置中断/proc/irq/${网卡中断号}/smp_affinit这时候,我也修改过,没有什么实质的效果,
从官方的bug报告,https://bugzilla.redhat.com/show_bug.cgi?id=520888,其中提到rhel5.6已经修复了这个bug,这其中也提到目前我们的版本可以升级内核到kernel-2.6.18-194.3.1.el5可以解决这个问题。
红帽子官方修复报告中的说明如下:http://rhn.redhat.com/errata/RHSA-2010-0398.html,我们升级了这个内核算是解决单核处理软中断的问题,升级后各个cpu已经能够平均的分配这个软中断,也不丢包了,那么为什么cpu处理不过来这个软中断呢,数据量并不是特别的大啊,上层应用接到这个数据包后,通过路由协议,找到某个出口给nat出去,找nat出口是需要查找路由表,查询路由表是一件很耗时的工作,而每一个不同源地址,不同目的地址的数据包都得重新查找一次路由表,导致cpu处理不过来,为了提高路由查询的效率。Linux内核引用了路由缓存,用于减少对路由表的查询。Linux的路由缓存是被设计来与协议无关的独立子系统,查看路由缓存可以通过命令route -Cn,由于路由缓存当中是采用hash算法进行才找,它的查找速度非常之快,既然是cache就有超时这一概念。系统默认为10分钟,可以通过这个文件进行查看和修改/proc/sys/net/ipv4/route/secret_interval。而当路由缓存当中未找到或者已经超时的路由信息才开始查找路由表,查询到的结果保存在路由缓存中。如果路由表越大,那么查询的时间就越长,一个新的连接进来后或者是老连接cache超时后,占用大量的cpu查询时间,导致cpu周期性的软中断出现100%,而两个网卡丢包的情况来看不均衡也是因为用户的数据包是经过其中一个网卡进来后查询路由表耗时过长,cpu处理不过来,导致那块网卡的队列满了,丢包严重。当然在路由表变动不大的情况下可以加大cache的时间,修改上述内容后,从我监测的情况来看,扛流量能力得到了大大的提升。