Linux network optimization
linux下监控网卡时可用的工具
ethtool
真正实现都是在网卡驱动中,所以这个工具较为重要。
1 | -i 显示网卡驱动的信息,名称,版本等 |
ifconfig
包含了一些网卡统计信息
1 | RX packets:接收的总包数 |
1 | /proc/net/dev 下有节点可以统计网卡工作数据 |
RingBuffer的监控与调优
当数据帧到达网卡,第一站即为RingBuffer,网卡通过DMA机制将数据帧送到RingBuffer中。因此第一个要监控和调优的就是网卡的RingBuffer.
ethtool -g eth0 可以查看Ringbuffer的大小。
在Linux的整个网络栈中,RingBuffer起到一个任务的收发中转站的角色。对于接收过程来讲,网卡负责往RingBuffer中写入收到的数据帧,ksoftirqd内核线程负责从中取走处理。只要ksoftirqd线程工作的足够快,RingBuffer这个中转站就不会出现问题。但是我们设想一下,假如某一时刻,瞬间来了特别多的包,而ksoftirqd处理不过来了,会发生什么?这时RingBuffer可能瞬间就被填满了,后面再来的包网卡直接就会丢弃,不做任何处理!
ethtool -S xx 或者 ifconfig xx都可以查看是否是因为这个原因丢包。
rx_fifo_errors如果不为0的话(在 ifconfig 中体现为 overruns 指标增长),就表示有包因为RingBuffer装不下而被丢弃了。那么怎么解决这个问题呢?很自然首先我们想到的是,加大RingBuffer这个“中转仓库”的大小。通过ethtool就可以修改。
1 | # ethtool -G eth1 rx 4096 tx 4096 |
这样网卡会被分配更大一点的”中转站“,可以解决偶发的瞬时的丢包。不过这种方法有个小副作用,那就是排队的包过多会增加处理网络包的延时。所以另外一种解决思路更好,那就是让内核处理网络包的速度更快一些,而不是让网络包傻傻地在RingBuffer中排队。
硬中断监控与调优
在数据被接收到RingBuffer之后,下一个执行的就是硬中断的发起。
监控
硬中断的情况 cat /proc/interrupts
对于收包情况,硬中断的总次数 不等于 Linux收包总数。因为,第一网卡可以设置中断合并,多个网络帧只可以发起一次中断,第二NAPI运行时 会关闭硬中断,通过poll来收包。
多队列网卡调优
目前主流网卡基本都是支持多队列的,可以通过将不同队列分为不同的CPU来处理,加快处理网络包的速度。(最为有用的一个优化手段)
每一个队列都有一个中断号,可以独立向某个CPU核心发起硬中断请求,让CPU来poll包。通过将接收进来的包被放到不同的内存队列里,多个CPU就可以同时分别向不同的队列发起消费了。这个特性叫做RSS(Receive Side Scaling,接收端扩展)。通过ethtool工具可以查看网卡的队列情况。
1 | ethtool -l eth0 |
如果你想提高内核收包的能力,直接简单加大队列数就可以了,这比加大RingBuffer更为有用。因为加大RingBuffer只是给个更大的空间让网络帧能继续排队,而加大队列数则能让包更早地被内核处理。ethtool修改队列数量方法如下:
1 | ethtool -L eth0 combined 32 |
硬中断合并
对于CPU来讲也是一样,CPU要做一件新的事情之前,要加载该进程的地址空间,load进程代码,读取进程数据,各级别cache要慢慢热身。因此如果能适当降低中断的频率,多攒几个包一起发出中断,对提升CPU的工作效率是有帮助的。所以,网卡允许我们对硬中断进行合并。
1 | ethtool -c eth0 |
软中断监控与调优
在硬中断之后,再接下来的处理过程就是ksoftirqd内核线程中处理的软中断了。之前我们说过,软中断和它对应的硬中断是在同一个核心上处理的。因此,前面硬中断分散到多核上处理的时候,软中断的优化其实也就跟着做了,也会被多核处理。不过软中断也还有自己的可优化选项。
监控设置
1 | cat /proc/softirqs 可以查看软中断信息 |
这个的意思说的是,ksoftirqd一次最多处理300个包,处理够了就会把CPU主动让出来,以便Linux上其它的任务可以得到处理。那么假如说,我们现在就是想提高内核处理网络包的效率。那就可以让ksoftirqd进程多干一会儿网络包的接收,再让出CPU。至于怎么提高,直接修改不这个参数的值就好了。
1 | sysctl -w net.core.netdev_budget=600 |
如果要保证重启仍然生效,需要将这个配置写到/etc/sysctl.conf
软中断GRO合并
GRO和硬中断合并的思想很类似,不过阶段不同。硬中断合并是在中断发起之前,而GRO已经到了软中断上下文中了。
如果应用中是大文件的传输,大部分包都是一段数据,不用GRO的话,会每次都将一个小包传送到协议栈(IP接收函数、TCP接收)函数中进行处理。开启GRO的话,Linux就会智能进行包的合并,之后将一个大包传给协议处理函数。这样CPU的效率也是就提高了。
1 | ethtool -k eth0 | grep generic-receive-offload |