netty学习十三:零拷贝底层实现原理

原创 2017年08月28日 20:15:42

零拷贝概述


零拷贝可以避免无谓的copy动作,为了说清楚这一点,本文会先从传统的读写操作开始介绍。


传统读操作


这里写图片描述

当应用发起一个从磁盘读取文件的操作时,请求会先经过内核,由内核与磁盘进行交互。数据会从磁盘拷贝到内核的缓存区中。这个copy动作由DMA完成,整个过程中基本上不消耗CPU。

DMA

硬件和软件的信息传输,可以使用DMA(direct memory access)来完成

如果应用想拿到信息,还得从内核缓冲区获取,这里又存在一个cpu copy的动作,将数据从内核缓冲区中拷贝到应用缓冲区中。这个copy动作是需要消耗CPU的。

如上文描述,要想从磁盘中读取出内容,需要2次copy动作。


传统写操作


这里写图片描述
应用想将数据传递给客户端,必须经过内核,将数据先从应用缓冲区中copy(cpu copy)到内核的缓冲区中,对于写操作而言,通常这个内核缓冲区叫

kernel socket buffer

接着DMA会从kernel socket buffer中将数据拷贝(DMA copy)到protocol engine,最终将数据发送给客户端。

这里又发生2次copy动作,一次是cpu copy,另外一次是DMA copy。

由此可见,当客户端对应用发起请求的时候,应用想将数据传递给客户端,期间需要经过4次数据拷贝动作,2次cpu copy,另外2次是DMA copy。期间应用程序相当于是一个中间者角色。

有没有办法将其中的2次cpu copy去掉呢?因为我们总是希望CPU能处理更多的事情,而不是浪费在这种无谓的copy操作当中。

答案是利用硬件以及操作系统内核,进行数据零拷贝


使用mmap()替代read()


在此之前,为了响应客户端的请求,并把数据发送给客户端,服务端进行了两个核心操作

read()
write()

在Linux中有一个mmap操作,可以减少拷贝次数,我们将read操作换成mmap操作

mmap()
write()

换成mmap操作后,仍然需要3次copy动作。

  • 第一次,DMA将数据从磁盘中拷贝(DMA copy)到kernel read buffer内核缓冲区中;
  • 第二次,当应用调用write方法时,会将kernel read buffer中的数据拷贝(CPU copy)到kernel socket buffer内核缓冲区;
  • 第三次,将kernel socket buffer中的数据拷贝到protocol engine(协议引擎)。

第二次为什么是cpu copy呢,因为是内存数据拷贝到另外的内存区域,必须CPU参与。

注意

在传统的读写操作中,是由应用将数据从应用缓冲区中写入到内核kernel socket buffer的。而使用mmap操作进行零拷贝时,由于不需要应用参与拷贝数据,CPU必须将数据从kernel read buffer中拷贝到kernel socket buffer。


使用sendfile()减少一次上下文切换


到此为止,已经减少了一次copy动作,但是使用

mmap()
write()

的组合还是有个缺点,就是应用调用write方法时,需求进行

应用mode到内核mode的一次切换

能不能在copy次数为3的情况下,将这次切换去掉呢?答案是使用

sendfile()

替换上面的

mmap()
write()

使用sendfile操作,copy次数还是为3,不过少了一次上下文切换。


去掉最后一个cpu copy


无论是使用

mmap()
write()

还是

sendfile()

仍然需要3次copy动作,两个是DMA copy,一个是cpu copy,能不能将这个cpu copy也去掉呢?

当然可以,需要借助DMA引擎的

gather操作

gather操作可以从多个不同的缓冲区中读取数据,DMA引擎是可以直接从kernel read buffer中读取数据的,而不用先将数据从kernel read buffer拷贝到kernel socket buffer后再进行读取操作。

到此,数据拷贝已经完全跟CPU没关系了,都是由内核操作的,内核只需要两次拷贝动作。

关于gather操作,可以参看Java NIO系列教程(四) Scatter/Gather


引用的文章


版权声明:本文为博主原创文章,未经博主允许不得转载。

理解Netty中的零拷贝(Zero-Copy)机制

理解零拷贝 零拷贝是Netty的重要特性之一,而究竟什么是零拷贝呢?  WIKI中对其有如下定义: “Zero-copy” describes computer operations...
  • wwwxxdddx
  • wwwxxdddx
  • 2016年04月21日 16:22
  • 1390

【总结】Netty(RPC高性能之道)原理剖析

1,Netty简述 Netty 是一个基于 JAVA NIO 类库的异步通信框架,用于创建异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性的网络客户端和服务器端RPC高性能分析,请参考文章...
  • zhiguozhu
  • zhiguozhu
  • 2016年01月14日 14:51
  • 12444

Linux 中的零拷贝技术

引言 传统的 Linux 操作系统的标准 I/O 接口是基于数据拷贝操作的,即 I/O 操作会导致数据在操作系统内核地址空间的缓冲区和应用程序地址空间定义的缓冲区之间进行传输。这样做最大的好处是...
  • q454684431
  • q454684431
  • 2016年03月31日 12:57
  • 6495

iOS 多线程编程<十三、NSOperation图片下载,SDWebImage底层实现原理>

NSOperation图片下载,SDWebImage底层实现原理 废话不多说,直接上代码: // // ViewController.m // DownLoadImage // /...
  • ZhengYanFeng1989
  • ZhengYanFeng1989
  • 2016年10月24日 14:00
  • 519

pytorch学习笔记(十三):backward过程的底层实现解析

博主水平有限,如有错误,请不吝指出。pytorch源码注释,欢迎 pr,提 issue 和 star当我们使用 pytorch 的 python 的接口编写代码的时候,感觉是十分清爽的,不需要考虑底层...
  • u012436149
  • u012436149
  • 2017年11月12日 12:05
  • 526

谈谈如何使用Netty开发实现高性能的RPC服务器(十三)

RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议。说的再直白一点,就是客户端在不必知道...
  • u011955252
  • u011955252
  • 2016年11月29日 17:18
  • 1167

DirectX学习笔记(十三):取景变换矩阵计算及3D世界摄像机的原理分析和实现

11
  • lishuzhai
  • lishuzhai
  • 2016年09月24日 14:07
  • 2727

零拷贝高速网络捕包原理与实现

  • 2008年11月13日 14:41
  • 672KB
  • 下载

Java并发之底层实现原理学习笔记

本篇博文将介绍java并发底层的实现原理,我们知道java实现的并发操作最后肯定是由我们的CPU完成的,中间经历了将java源码编译成.class文件,然后进行加载,然后虚拟机执行引擎进行执行,解释为...
  • qq_39266910
  • qq_39266910
  • 2018年01月06日 16:24
  • 36

golang基础-数组、切片创建_内存_底层实现_修改值_拷贝_循环、string与切片

数组 数组:是同一种数据类型的固定长度的序列 数组定义:var a [len]int,比如:var a[5]int,一旦定义,长度不能变 长度是数组类型的一部分,因此,var a[5] int和...
  • u013210620
  • u013210620
  • 2017年10月23日 23:26
  • 145
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:netty学习十三:零拷贝底层实现原理
举报原因:
原因补充:

(最多只允许输入30个字)