原理概述:
零拷贝是一种特殊形式的内存映射,它允许你直接将Kernal内存直接映射到设备内存空间上。说白了就是设备可以通过直接内存访问(DMA,direct memory access )方式来访问Kernal Space。
我们以kafka为例,kafka会对流数据做持久化,这意味着consumer消费数据时,会从硬盘直接读出数据,原封不动通过socket传输给用户。
这种操作看起来不怎么消耗cpu,但实际上很低效:kernal把数据从disk读出来,然后传输给user级别的application,然后application再把数据原传回kernal级的socket。所以这种情况下,application实际上做了低效的中间件。
上述操作如下图:
所以我们通过网络传输数据时,尽管看起来简单,但在OS内部,这个copy操作要进行4次user model和kernal model之间的上下文切换,而数据都被拷贝了四次!而且每次数据穿过user-kernal boundary时,都会被copy,浪费cpu,占用RAM带宽。于是kafka底层使用了Zero Copy技术来改善这种情况。
宏观来看,我们发送一个文件,却要拷贝四次,性能很低。那要具体怎么做呢?在上图中,我们可以砍掉红线的两次拷贝,直接从read buffer 发送到NIC buffer(网卡缓冲区)。
优化后的效果图:
从上图可以看到,在零拷贝模式下,避免了数据在用户空间和内核空间的复制,从而提高系统整体性能。Linux的sendfile()和java NIO中的FileChannel.transferTo()方法都实现了零拷贝技术。