《深入理解Linux网络》第四章读书笔记
原创- 2023-12-21 15:21:43
- 1000
本篇目录
网络发包具体流程啥样?
为什么查看/proc/softirqs,NET_RX比NET_TX大的多?
首先要将NET_RX、NET_TX与UART等协议中的TX、RX区别开来,在Linux中,RX并不只接收数据、TX并不只发送数据,所以原因有二:
- 一是:当数据发送完毕时,通过硬中断的方式来通知驱动发送完毕。但是硬中断无论是
数据接收
,还是发送完毕
,触发的软中断都是NET_RX_SOFTIRQ
,并不是NET_TX_SOFTIRQ。 - 二是:对于读来说,都是要经过NET_RX软中断的,都走ksoftirqd内核线程。而对于发送来说,绝大部分工作都是在用户进程内核态处理了,只有系统态配额用尽才会发送NET_TX,让软中断上。
综上,导致了NET_RX比NET_TX大的多。
发送网络数据的时候涉及的内存拷贝操作(此处内存拷贝,只指待发送数据的内存拷贝)
- 第一次:在内核申请完skb后,会将用户传递进来的buffer里的数据内容都拷贝到skb。(如果发送数据比较大,此次拷贝开销也会较大)
- 第二次:从传输层进入网络层的时候,每一个skb都会被克隆出来一个新的副本。目的是保存原始的skb,当网络对方没有回应ack时,还可以重新发送,以实现
可靠传输
。此处拷贝为浅拷贝,所指向的数据还是复用的。 - 第三次(非必需):当IP层发现skb大于MTU时才需进行。此时会再申请额外的skb,并将原来的skb拷贝为多个小的skb。
啥是零拷贝?
通过sendfile系统调用来举例:如果要将本机的一个文件发送出去,做法之一是先用read系统调用把文件读取到内存,然后再调用send将文件发送出去。- 假设数据之前从来没有读取过,那么read硬盘上的数据需要经过两次拷贝才能到用户进程的内存。第一次是从硬盘DMA到Page Cache。第二次是从Page Cache拷贝到用户内存。
- 此时,前面提到的sendfile就派上用场了,再sendfile系统调用中,数据不需要拷贝到用户空间,在内核态就可以完成发送处理,显著减少了需要拷贝的次数。
题外话:为什么Kafka网络性能突出?
结合本章内容可以知道一个重要原因:Kafka采用了sendfild
系统调用来发送网络数据包,减少了内核态和用户态之间的频繁数据拷贝。