一文掌握目前主流的零拷贝技术

2022-11-11 17:20:55 浏览数 (1)

现在只要涉及到存储,涉及到和文件相关的开源框架,几乎都不约而同的会使用零拷贝技术,因为零拷贝技术可以让速度变快。零拷贝技术并不是说完全不拷贝,而是尽可能的减少拷贝。

在没有零拷贝技术之前,你操作一个文件一般是这样的流程:

  • 应用调用read方法,初始化一个IO向操作系统发起调用,context上下文从user mode切换到kernel mode;
  • DMA控制器把数据从磁盘读取到kernel buffer;
  • CPU读取 kernel buffer里的数据,然后把数据拷贝到用户应用程序buffer(user buffer)context上下文从kernel mode切换到user mode。read方法return;
  • 用户应用进程通过write方法初始化一个IO调用,context从user mode切换到kernel mode,然后拷贝数据到socket buffer;
  • DMA控制器再把数据从socket buffer拷贝到network card(网卡),write方法返回时context从kernel mode 切换到user mode。

你可以发现一共进行了4次拷贝,两次DMA拷贝,两次CPU拷贝,并且你会发现发生了4次user space和kernel space之间的切换。

在IO的世界里,拷贝和上下文切换都是非常昂贵的,这一切都源于CPU的介入。为了安全,凡事都得经过CPU这一关,但这也带来一个问题就是性能下降。为此,计算机界的大佬们苦苦研究和探索,想着如何让CPU不介入或者减少介入,最后他们终于探索出两大零拷贝技术:mmap、sendfile。

ps:其实上面那个DMA拷贝也是一个减少CPU介入的更加快速的方案。

那我们接下来就来看看这两种零拷贝技术分别是怎么实现的。

mmap

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

什么是MMAP技术呢?其实就是虚拟内存技术,磁盘即内存,内存即磁盘。

相比 read() 方法,mmap技术主要的不同是向操作系统内核发起IO调用的mmap方法。通过MMAP技术,你会发现减少了一次CPU的拷贝,一共是三次拷贝:两次DMA拷贝和一次CPU拷贝。具体步骤:

  • 用户进程初始化一个IO,通过mmap方法向操作系统内核发起调用,此时context从user mode切换到kernel mode;
  • CPU通过DMA控制器把数据从硬件拷贝到内核的buffer里;
  • 此刻context从kernel mode切换到user mode,mmap方法return;
  • 然后用户进程通过write方法向操作系统内核再次发起一次IO调用把数据写入socket buffer中,然后context从user mode切换到kernel mode;
  • 然后CPU使用DMA控制器把数据从socket buffer拷贝到network card(网卡)然后context从kernel mode切换到user mode,wirte方法 return。

sendfile

ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

sendfile方法是直接面向fd的,也就是file descriptor的,文件描述符,sendfile让两个fd之间直接传输数据,这个动作是在操作系统内核层执行,这样就避免了内核buffer和user buffer之间的数据拷贝操作,所以它也被称为是一种零拷贝技术。具体流程如下:

  • 用户进程初始化一个sendfile的系统调用(system call),然后context从user mode切换到kernel mode;
  • DMA控制器把数据从硬盘复制到内核buffer中;
  • 然后CPU直接把把内核buffer中的数据复制到socket buffer中;
  • DMA控制器异步把数据从socket buffer复制到网卡(network card)
  • context从kernel mode切换到user mode,sendfile方法return。

可以发现基于sendfile的零拷贝技术只有两次context的切换,3次拷贝(2次DMA拷贝、1次CPU拷贝)。

这里需要注意的是sendfile和mmap同样都发生了3次拷贝,但在上下文切换上sendfile比mmap少了两次,mmap切换了4次,但sendfile只有两次切换。所以从性能上讲sendfile更出色。

Kafka和RocketMQ

众所周知这两个MQ框架有异曲同工之妙,犹如孪生兄妹一般,但据笔者所知他们之间还是有一些不同的,其中一个重要的不同就是使用的零拷贝技术不同,RocketMQ使用的mmap技术,而Kafka则使用的sendfile技术。

总结

通过上面的分析,我们知道了两种主要的零拷贝技术:mmap和sendfile。这两个零拷贝技术都有效地减少了拷贝次数,都是三次拷贝,同时sendfile还减少了context切换的次数,变成了2次。同时我们知道了Kafka和RocketMQ他们使用了不同的零拷贝技术。目前只要涉及到存储和文件相关的开源框架为了提高性能几乎都会使用到零拷贝技术,比如IO框架(Netty)、MQ、分布式NoSQL数据库等。

0 人点赞