[翻译] Bulk network packet transmission

Bulk network packet transmission

译文作者:zhangzl2013
译文链接:http://www.cnblogs.com/zhangzl2013/p/bulk_network_packet_transmission.html
原文作者:Jonathan Corbet
原文链接:Bulk network packet transmission
本文有可能会被转载,从而导致评论留言的碎片化。想参与评论和探讨的同学,请找到原文或译文的原始地址,与原文或译文作者互动讨论。

批量处理是当代系统提升性能的关键因素之一——在相对固有开销之内尽可能做更多的事情。比如,如果某个子系统在做某些事情时必须要获得锁,那么在获得一次锁的时候尽可能的把这类事情都做完能够减少系统总开销。最近几年通过尽可能增加批量处理操作来提升性能的工作已经做了不少。最近对网络子系统增加批量处理操作,也让它的性能有所提高。

每次在网络中传输一个数据包时,都需要做一些列的操作。包括获取发送队列的锁,把数据包传递给驱动,把数据包插入设备传输队列并通知设备开始传输。有一些操作必然是要针对每个数据包的,但有不是。例如,获取队列锁的操作就不是,通知设备开始传输的开销也很大。它涉及到硬件操错,在某些系统上还涉及到特权指令调用。

在传输一个数据包时,队列中通常会有其他数据包;而网络通信本身是可以丛发传输的。所以网络协议栈可以试着把固有开销平均到多个数据包上。 segmentation offload技术就会做类似的批量处理优化。但是当前的内核中,如果网络栈中有一系列的数据包要发送,也是每次一个这种低效的方式来发送。

这种情况在3.18中合并了一个小补丁集后会有所改变。看一些下面这个驱动导出的发送数据包的函数:

netdev_tx_t    (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev);

此函数获取一个skb指针,通过dev设备将它发送出去。每次调用都是一个独立的操作,会有固定的开销。3.18中,计划给驱动添加一个新函数:

void (*ndo_xmit_flush)(struct net_device *dev, u16 queue);

如果驱动提供这个函数,就说明网络栈可以进行批量传输。网络栈可以接受多次ndo_start_xmit()函数调用,但驱动并不开始发送。在一系列的调用之后,再调用ndo_xmit_flush()函数来使驱动开始真正的传输。

考虑到在传输路径上增加一个函数调用又增加了开销,所以这个函数几乎刚加入代码库就又去除了。取而代之的是在sk_buff结构体中增加了一个新的布尔型变量xmit_more。如果它为真,意味着还有更多数据包要传,驱动可以推迟硬件传输。这个变量使得在给驱动提供足够的信息的同时而又不必引入新的函数。

David Miller添加的这个机制实现了批量操作。一些驱动做了相应的支持,但是David没有亲自修改网络栈,而是由Jesper Dangaard Brouer在3.18中添加“bulk dequeue”补丁实现的。目前它的范围也不大,只是用于单个传输队列的情况中。

Jesper的改动很小:在有数据包要传输时,网络栈会尽量在获得锁之后一次性发送更多的数据包。“byte queue limit”机制限制了最大等待的数据数量。一旦达到这个上限,skb->xmit_more会置为假,从而开始真正的传输。

Eric Dumazet发现这个补丁集还可以进一步改进:确认数据包传输的工作可以完全放在队列锁之外,从而增加系统的并发性。Eric的补丁效果巨好:即使不用segmentation offload技术,也能达到40Gb每秒的速度。毫无疑问,这个补丁已经合并进了3.18.

改动虽然很小,但是小改动可以带来大影响。这个小改动使3.18内核拥有目前最快的网络栈。

-- 结束 --

posted @ 2014-10-21 07:43 zhangzl2013 阅读(...) 评论(...) 编辑 收藏