Linux会对一个网络包(packet)的收和发做大量的处理。packet在被发送之前会被存在队列中,而在被接受之后也会存在队列中,共有三个队列:reception(接收),transmission(发送)和Backlog。它们都受到spinlock的保护,是为了保证在并发访问时的一致性。言归正传,接下来看看当一个packet到达NIC(网卡)时,linux都会做些什么工作。
先来看一个图(来自论文 Analysis of Linux UDP Sockets Concurrent Performance)
1)先触发硬中断(HardIRQ),再进行软中断(SoftIRQ)。
2)软中断执行过程中的Lower Processing处理会将packet从L2层送到L4层。
3)接下来就是packet入队,同步原语会影响到收包性能。(再之后就是被应用程序读取)
更详细的收包过程可以看这篇文章:The performance analysis of linux networking – packet receiving。
就拿收包来说,在被应用程序读到之前,linux要将其从网卡搬到内核内存(kernel‘s memory),但是一个socket只能使用有限制的内核内存来存包,否则会让内核内存溢出(overflow)。
在普通的i5笔记本上,我们发现一次socket的loopback的TCP的发(client)和收(server)要耗时100~200 us。而loopback的带宽可以达到30~40Gbps,所以并不是网络传输产生这样的延迟(latency)。通过上面的分析,当server这端的网卡收到包时,会经过一系列的步骤才能被用户程序读取,这一过程包括触发中断,内核内存拷贝,进入带锁的队列,等。会不会是这些操作占据了大部分时间,现在仍不能断言就是,仍然需要更确凿的证据。