IO模型-网络IO与零拷贝

网络I/O与零拷贝

普通的网络传输步骤如下

  • 操作系统将数据从磁盘复制到操作系统内核的页缓存中
  • 应用将数据从内核缓存复制到应用的缓存中
  • 应用将数据写回内核的Socket缓存中
  • 操作系统将数据从Socket缓存区复制到网卡缓存,然后将其通过网络发出

普通的网络传输

  • 当调用read系统调用时,通过DMA(Direct Memory Access)将数据copy到内核模式
  • 然后由CPU控制将内核模式数据copy到用户模式下的 buffer中
  • read调用完成后,write调用首先将用户模式下 buffer中的数据copy到内核模式下的socket buffer中
  • 最后通过DMA copy将内核模式下的socket buffer中的数据copy到网卡设备中传送

从上面的过程可以看出,数据白白从内核模式到用户模式走了一圈,浪费了两次copy,而这两次copy都是CPU
copy,即占用CPU资源

sendfile/零拷贝(kafka用到此特性)

零拷贝

通过sendfile传送文件只需要一次系统调用,当调用 sendfile时:

  • 首先通过DMA copy将数据从磁盘读取到kernel buffer中
  • 然后通过CPU copy将数据从kernel buffer copy到sokcet buffer中
  • 最终通过DMA copy将socket buffer中数据copy到网卡buffer中发送

sendfile与read/write方式相比,少了 一次模式切换一次CPU copy。但是从上述过程中也可以发现从kernel buffer中将数据copy到socket buffer是没必要的

改进版零拷贝

改进版零拷贝

改进后的处理过程如下:

  • DMA copy将磁盘数据copy到kernel buffer中
  • 向socket buffer中追加当前要发送的数据在kernel buffer中的位置和偏移量
  • DMA gather copy根据socket buffer中的位置和偏移量直接将kernel buffer中的数据copy到网卡上

经过上述过程,数据只经过了2次copy就从磁盘传送出去了。(事实上这个Zero copy是针对内核来讲的,数据在内核模式下是Zero-copy的)。当前许多高性能http server都引入了sendfile机制,如nginx,lighttpd等

觉得文章有用的话,欢迎点赞打赏~