Netty 零拷贝(一)Linux 零拷贝

本文探讨 Linux 中主要的几种零拷贝技术以及零拷贝技术适用的场景。

一、几个重要的概念

1.1 用户空间与内核空间

操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核 (kernel),保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。

1.2 IO 两个流程

网络 IO 的本质是 socket 的读取,socket 在 linux 系统被抽象为流,IO 可以理解为对流的操作。刚才说了,对于一次 IO 访问 (以 read 举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个 read 操作发生时,它会经历两个阶段:

  • 第一阶段:等待网络上的数据分组到达,然后被复制到内核的某个缓冲区 (Waiting for the data to be ready)。
  • 第二阶段:把数据从内核缓冲区复制到应用进程缓冲区 (Copying the data from the kernel to the process)。

本文关注的是第二个过程:如何减少拷贝,即零拷贝。

二、传统的 IO 流程

Linux 的 I/O 操作默认是缓冲 I/O。使用了 read 和 write 两个系统调用,我们并不知道操作系统在其中做了什么。实际上在以上 I/O 操作中,发生了多次的数据拷贝。

当应用程序访问某块数据时,操作系统首先会检查,是不是最近访问过此文件,文件内容是否缓存在内核缓冲区,如果是,操作系统则直接根据 read 系统调用提供的 buf 地址,将内核缓冲区的内容拷贝到 buf 所指定的用户空间缓冲区中去。如果不是,操作系统则首先将磁盘上的数据拷贝的内核缓冲区,这一步目前主要依靠 DMA 来传输,然后再把内核缓冲区上的内容拷贝到用户缓冲区中。
接下来,write 系统调用再把用户缓冲区的内容拷贝到网络堆栈相关的内核缓冲区中,最后 socket 再把内核缓冲区的内容发送到网卡上。

整个过程中共产生了多次数据拷贝,即使用了 DMA 来处理了与硬件的通讯,用户空间和系统空间 CPU 仍然需要处理两次数据拷贝,与此同时,在用户态与内核态也发生了 4 次上下文切换,无疑也加重了 CPU 负担。

  1. 通过 DMA copy 数据从 hard drive 拷贝到 kernel buffer
  2. 通过 CPU copy 数据从 kernel buffer 拷贝到 user buffer
  3. 通过 CPU copy 数据从 user buffer 拷贝到 kernel buffer
  4. 通过 CPU copy 数据从 kernel buffer 拷贝到 socket buffer
  5. 通过 DMA copy 将 socket buffer 中的数据发送出去

在此过程中,我们没有对文件内容做任何修改,那么在内核空间和用户空间来回拷贝数据无疑就是一种浪费,而零拷贝主要就是为了解决这种低效性。

三、零拷贝(zero-copy)

3.1 零拷贝概念

零拷贝主要的任务就是避免 CPU 将数据从一块存储拷贝到另外一块存储,主要就是利用各种零拷贝技术,避免让 CPU 做大量的数据拷贝任务,减少不必要的拷贝,或者让别的组件来做这一类简单的数据传输任务,让 CPU 解脱出来专注于别的任务。这样就可以让系统资源的利用更加有效。

如何减少数据拷贝的次数呢?一个很明显的着力点就是减少数据在内核空间和用户空间来回拷贝,这也引入了零拷贝的一个类型:减少用户空间到内核空间的拷贝。

2.2 减少用户空间和内核空间的拷贝

应用程序调用 sendfile,磁盘上的数据会通过 DMA 被拷贝的内核缓冲区,接着操作系统会把这段内核缓冲区与应用程序共享,这样就不需要把内核缓冲区的内容往用户空间拷贝。应用程序再调用 write(),操作系统直接将内核缓冲区的内容拷贝到 socket 缓冲区中,这一切都发生在内核态,最后,socket 缓冲区再把数据发到网卡去。

目前为止,我们已经减少了数据拷贝的次数,但是仍然存在一次拷贝,就是页缓存到 socket 缓存的拷贝。那么能不能把这个拷贝也省略呢?

2.3 直接传递文件描述符

在上一种方案中是将页缓存的数据拷贝到 socket 缓存中,实际上,我们仅仅需要把缓冲区描述符传到 socket 缓冲区,再把数据长度传过去,这样 DMA 控制器直接将页缓存中的数据打包发送到网络中就可以了。不过这种收集拷贝功能是需要硬件以及驱动程序支持的。

在服务端响应客户端的场景中,如果使用非直接缓冲区第一步就需要将响应的数据从 JVM 内存拷贝到系统内核中再发送,而使用直接缓冲区就可以省略这个步骤,这就是 零拷贝

四、总结

传统的 IO 读和写都需要在操作系统内核和用户空间之间拷贝,Linus 优化了内核空间和用户空间的拷贝过程,内核空间也可以通过传递文件描述符进一步减少内核中的一次拷贝过程。Linux 零拷贝演进过程:


每天用心记录一点点。内容也许不重要,但习惯很重要!

Netty 零拷贝(一)Linux 零拷贝的更多相关文章

  1. Linux、JDK、Netty中的NIO与零拷贝

    一.先理解内核空间与用户空间 Linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应着下图中, CPU 特权等级分为4个,Linux 使用 Ring 0 和 Ring 3. 内核空 ...

  2. NIO学习笔记,从Linux IO演化模型到Netty—— Linux零拷贝

    这里只是感性地认识Linux零拷贝,不涉及具体细节. 1.Linux传统的数据拷贝 用户进程是不能直接访问文件系统的,要先切换到内核态,发起系统调用,DMA把磁盘中的数据写入内核空间,内核再把数据拷贝 ...

  3. 框架篇:Linux零拷贝机制和FileChannel

    前言 大白话解释,零拷贝就是没有把数据从一个存储区域拷贝到另一个存储区域.但是没有数据的复制,怎么可能实现数据的传输呢?其实我们在java NIO.netty.kafka遇到的零拷贝,并不是不复制数据 ...

  4. 【Netty技术专题】「原理分析系列」Netty强大特性之ByteBuf零拷贝技术原理分析

    零拷贝Zero-Copy 我们先来看下它的定义: "Zero-copy" describes computer operations in which the CPU does n ...

  5. Linux零拷贝技术,看完这篇文章就懂了

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,欢迎大家关注,二维码文末可以扫. 本文讲解 ...

  6. Linux零拷贝技术 直接 io

    Linux零拷贝技术 .https://kknews.cc/code/2yeazxe.html   https://zhuanlan.zhihu.com/p/76640160 https://clou ...

  7. Linux零拷贝技术

    本文转载自Linux零拷贝技术 导语 本文讲解 Linux 的零拷贝技术,云计算是一门很庞大的技术学科,融合了很多技术,Linux 算是比较基础的技术,所以,学好 Linux 对于云计算的学习会有比较 ...

  8. Linux零拷贝原理

    Linux零拷贝原理 前言 磁盘可以说是计算机系统最慢的硬件之一,读写速度相差内存 10 倍以上,所以针对优化磁盘的技术非常的多,比如零拷贝.直接 I/O.异步 I/O 等等,这些优化的目的就是为了提 ...

  9. 将文件从一台linux机器拷贝到多台的方法

    首先你所操作的各台linux机器间必须设置了ssh免密码登录,具体方法可上网查看.将文件从一台linux机器拷贝到多台分为以下几个步骤: 第一步:创建脚本文件remotecopy.sh #!/bin/ ...

随机推荐

  1. python入门-变量和简单数据类型

    1 title() 是以首字母大写的方式显示每个单词 lower() 字母小写 upper() 字母大写 2 python使用+号来合并字符串 字符串中使用制表符用\t 字符串中使用换行符\n 用rs ...

  2. hdu 4370 0 or 1,最短路

    题目描述 给定n * n矩阵C ij(1 <= i,j <= n),我们要找到0或1的n * n矩阵X ij(1 <= i,j <= n). 此外,X ij满足以下条件: 1. ...

  3. mysql 数据字典

    Information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式. desc tb_name ,describe tb_name,show columns from tb_ ...

  4. HTML5 Canvas ( 图形变换矩阵 ) transform, setTransform

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. JS吧数字转成2进制 8进制16进制数据

    ; number.toString(); //转成2进制 number.toString();//转成8进制 number.toString();//转成10进制 number.toString(); ...

  6. python常见异常提示

    PEP8 expected 2 blank lines, found 1 定义方法时,出现期望是2个空白行,但是实际检测到是1个.方法与上面内容间隔期望为两个换行符 PEP8 This diction ...

  7. eclipse在运行main方法时在console里面报内存溢出的错误解决办法

    修改JVM的配置. window-->preferences-->Java-->installedJres选中使用的jdk/jre版本 点击右边的edit在弹出的对话框中的[Defa ...

  8. AMD 与CMD

    AMD AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义".它采用异步方式加载模块,模块的加载不影响它后面 ...

  9. PYTHON-进阶-装饰器小结,转载

    本文转载自:http://www.wklken.me/posts/2012/10/27/python-base-decorator.html 基本概念 具体概念自己google 装饰器是一个很著名的设 ...

  10. Nginx_status显示结果详解

    打开:http://aabb.com/nginx_status会有如下显示Active   connections: 2872server   accepts  handled requests294 ...