写点什么

程序员你了解零拷贝吗?

作者:Java高工P7
  • 2021 年 11 月 12 日
  • 本文字数:1229 字

    阅读完需:约 4 分钟


上图是 JAVA 传统的写操作,具体流程:


1、应用发起写操作,OS 进行一次上下文切换(从用户空间切换为内核空间)

2、并且把数据 copy 到内核缓冲区 Socket Buffer,做了一次 CPU Copy

3、内核空间再把数据 copy 到磁盘或其他存储(网卡,进行网络传输),进行了 DMA Copy

4、写入结束后返回,又从内核空间切换到用户空间

传统 IO

我们可以看出传统的 IO 读写操作,总共进行了 4 次上下文切换,4 次 Copy 动作。我们可以看到数据在内核空间和应用空间之间来回复制,其实他们什么都没有做,就是复制而已,这个机制太浪费时间了,而且是浪费的 CPU 的时间


那我们能不能让数据不要来回复制呢?零拷贝这个技术就是来解决这个问题。关于零拷贝提供了两种解决方式:mmap+write 方式、sendfile 方式

虚拟内存

所有现代操作系统都使用虚拟内存,使用虚拟地址取代物理地址,这样做的好处就是:


1、多个虚拟内存可以指向同一个物理地址


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


2、虚拟内存空间可以远远大于物理内存空间


我们利用第一条特性可以优化一下上面的设计思路,就是把内核空间和用户空间的虚拟地址映射到同一个物理地址,这样就不需要来回复制了,看图:


mmap+write 方式

使用 mmap+write 方式替换原来的传统 IO 方式,就是利用了虚拟内存的特性,看图



整体流程的核心区别就是,把数据读取到内核缓冲区后,应用程序进行写入操作时,直接是把内核的 Read Buffer 的数据复制到 Socket Buffer 以便进行写入,这次内核之间的复制也是需要 CPU 参与的


注意:最后把 Socket Buffer 数据拷贝到很多地方,统称 protocol engine(协议引擎)


这个流程就少了一个 CPU Copy,提升了 IO 的速度。不过发现上下文的切换还是 4 次,没有减少,因为还是要应用程序发起 write 操作。那能不能减少上下文切换呢?

sendfile 方式

这种方式可以替换上面的 mmap+write 方式,如:


mmap();write();


替换为


sendfile();


这样就减少了一次上下文切换,因为少了一个应用程序发起 write 操作,直接发起 sendfile 操作。到这里就只有 3 次 Copy,其中只有 1 次 CPU Copy;3 次上下文切换。那能不能把 CPU Copy 减少到没有呢?

gather

Linux2.4 内核进行了优化,提供了 gather 操作,这个操作可以把最后一次 CPU Copy 去除,什么原理呢?就是在内核空间 Read Buffer 和 Socket Buffer 不做数据复制,而是将 Read Buffer 的内存地址、偏移量记录到相应的 Socket Buffer 中,这样就不需要复制(其实本质就是和虚拟内存的解决方法思路一样,就是内存地址的记录),如图:


JAVA 零拷贝

java nio 实现零拷贝,JAVA 提供了一下方法类:


1、MappedByteBuffer2、DirectByteBuffer3、FileChannel.transferTo


具体如何使用,小伙伴们上网自行查阅。

总结

零拷贝技术在很多中间件中,都有利用;如:Kafka,Spark、RocketMQ 等,这个在网络传输数据时,能够提升速度,提升系统性能、吞吐量。小伙伴们不一定会编写,可以先了解基本原理就行。很多好的中间件产品都需要了解一些计算机原理方面的知识,才会更深入的理解。

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
程序员你了解零拷贝吗?