ZeroCopy

本文将简单介绍一下零拷贝的原理。

传统的IO

服务器在对静态文件进行处理时,需要从硬盘读取静态文件,然后再通过socket返回数据。

在这个过程中,数据在内核和用户态之间切换,都会进行数据复制,影响数据传输的效率。

网络请求的四次内存拷贝

DMA(Direct Memory Access)被译为直接内存访问,无需借助于CPU

① 【DMA拷贝】磁盘到内核态的拷贝(DMA拷贝),写入Read Buffer(读缓冲区)

② 【CPU拷贝】内核态到用户态的拷贝;

③ 【CPU拷贝】用户态到内核态的拷贝,写入Socket Buffer(Socket缓冲区)

④ 【DMA拷贝】内核态到NIC Buffer(网卡缓冲区)

 4 copy

网络请求的三次上下文切换

read命令通过系统调用从用户态进入内核态

② 上一步的系统调用数据从内核态拷贝到用户态;

write命令通过系统调用从用户态拷贝到内核态

 3 switch

ZeroCopy

ZeroCopy(零拷贝)是通过避免不必要的拷贝和上下文切换来提高性能的。

sendfile

sendfile是为了解决网络传输的性能问题,也就是磁盘到网卡之间的传输效率。

拷贝次数降低为3次:2次DMA拷贝,1次CPU拷贝

切换次数降低为2次:从用户态进入内核态,从内核态返回用户态

 3 copy

同时,上下文切换也降低为两次,操作均在内核态完成。

 2 switch

由于sendfile操作均在内核态完成,因此用户无法对数据进行更改。

sendfile & DMA gather

sendfile的基础之上,利用DMA gather操作把Read Buffer的数据描述信息(内存地址、地址偏移量)记录到Socket Buffer,再根据描述信息将数据批量地从Read Buffer直接拷贝到NIC Buffer(网卡缓冲区)

拷贝次数降低为2次:2次DMA拷贝

 2 copy

应用场景

NginxLighttpd都使用了sendfile方法来实现高效的内存拷贝。

KafkaNetty都利用transferTo同样使用零拷贝来实现数据的内核态处理,避免了多次拷贝操作。