禅道博客

分享专业技术知识,文章内容干货满满

《深入理解Linux网络》第四章读书笔记

2022-11-01 10:00:00
刘永凯
原创 89
摘要:本次主要分享了《深入理解Linux网络》第四章及第三章的知识,梳理内核的发包等相关内容。

网络发包具体流程啥样?

为什么查看/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 系统调用来发送网络数据包,减少了内核态和用户态之间的频繁数据拷贝。
发表评论
评论通过审核后显示。