Zero-Copy

Zero-Copy零拷贝

Zero-Copy用于提高Linux平台上的IO密集型的应用程序的性能。能够避免中间缓冲区中的冗余数据复制以及减少Linux内核空间和用户空间上下文交换的次数。

Zero-Copy使得应用程序从本地磁盘读取数据,再将读取的数据原封不动直接地发送给Socket。

传统数据传输过程

数据先从本地磁盘读取到内核空间中,再通过缓冲区由用户程序得到,用户程序再通过缓冲区将数据发送到Socket。

即:

  • 本地磁盘->内核buffer:用户态->内核态
  • 内核buffer->用户buffer:内核态->用户态
  • 用户buffer->socket buffer:用户态->内核态
  • socket buffer->协议引擎:内核态->用户态

这个过程当中一共出现了4次数据拷贝和4次用户态-内核态的上下文切换。

每次数据传输到内核-用户缓冲区时,必须进行复制,这消耗了CPU和内存,通过zerocopy请求使得数据直接从内核发送到Socket。
即:

  • 本地磁盘->内核buffer:用户态->内核态
  • 内核buffer->socket buffer:内核态->内核态
  • socket buffer->协议引擎:内核态->用户态
    这个过程当中一共出现了3次数据拷贝和2次用户态-内核态的上下文切换。

transferTo

JAVA类库通过java.nio.channels.FileChannel. transferTo()方法支持zerocopy技术。

transferTo() 方法将数据从一个文件channel传输到一个可写channel。在内部它依赖于操作系统对 Zero-copy 的支持,在UNIX/Linux系统上, transferTo() 实际会调用 sendfile() 这个系统函数,将数据从一个文件描述符传输到另一个。

与传统方法相比,使用transferTo()API可减少大约65%的时间。这对于需要将大量数据从一个I / O通道复制到另一个I / O通道的应用程序(如Web服务器)来说可以显著提高性能。

内核态和用户态

内核态:cpu可以访问内存的所有数据,包括外围设备,例如硬盘,网卡,cpu也可以将自己从一个程序切换到另一个程序。

用户态:只能受限的访问内存,且不允许访问外围设备,占用cpu的能力被剥夺,cpu资源可以被其他程序获取。

为什么要有用户态和内核态?

由于需要限制不同的程序之间的访问能力, 防止他们获取别的程序的内存数据, 或者获取外围设备的数据, 并发送到网络, CPU划分出两个权限等级 – 用户态和内核态。

用户态与内核态的切换

所有用户程序都是运行在用户态的,但是有时候程序确实需要做一些内核态的事情,例如从硬盘读取数据, 或者从键盘获取输入等。

而唯一可以做这些事情的就是操作系统,所以此时程序就需要先操作系统请求以程序的名义来执行这些操作。

用户态切换到内核态的唯一途径:中断/异常/陷入
内核态切换到用户态的途径:设置程序状态字

------ 本文结束------

本文标题:Zero-Copy

文章作者:Perkins

发布时间:2019年11月30日

原始链接:https://perkins4j2.github.io/posts/20850/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。