随着网络数据的增加,传统的Linux网络栈的性能限制越来越引起人们的关注。
首先,我们来看一下Linux协议栈是如何处理网络数据包的
网卡接收到一个数据包
|
送到网卡的接收队列(RX)
|
通过DMA方式拷贝到内存
|
系统收到通知:有新的数据包
|
软中断
|
内核为每个数据包分配buffer(sk_buff)
|
传输数据包到userspace
这种机制在接收大量数据包时,存在如下瓶颈:
1)分配sk_buff内存给每个数据包,并在数据包传送到用户态时释放内存。这个过程需要消耗大量的总线cycle(从CPU传输数据到内存);
2)为了尽可能多的兼容各种网络协议,Sk_buff结构体的成员变量中有很多的元数据。而这些元数据在处理某类数据包时并不是必需的。这种负责的结构体也导致数据包的处理变慢;
3)当用户态的应用发送或者接收数据包时,需要进行系统调用。因此,上下文需要先切换到内核态,然后又回到用户态。这个重复的过程也会消耗大量的系统资源。
为了解决上述问题,Linux内核从2.6以后引入了NAPI(NewAPI)。其工作原理大致如下:
网卡正常工作在中断模式下
|
数据包被送到网卡
|
网卡注册自己到polling队列,并且disable中断
|
(系统定期地检查队列,查看有无新的设备)
|
收集数据进行处理
|
网卡从polling队列中删除,并使能中断
这种做法依然有问题,需要不停的在使能或者关闭中断。