文章目录

  • 文件传输(读取与发送)中的拷贝与上下文切换
  • 零拷贝技术
    • sendfile
    • sendfile + SG-DMA
    • mmap + write
    • splice
    • Direct I/O
  • 经典应用

文件传输(读取与发送)中的拷贝与上下文切换

如果服务端要提供文件传输的功能,最简单的方式是:
1、将磁盘上的文件读取出来
2、通过网络协议将内容发送给客户端
传统IO的工作方式是,数据读取和写入从用户空间到内核空间来回赋值,内核空间数据通过IO接口从磁盘读取/写入。
就如同下面这两个api的使用:

File.read(file, buf, len);
Socket.send(socket, buf, len);

这个场景下会发生4次数据拷贝+4次上下文切换
read系统调用,从用户态到内核态 切换 ,CPU从磁盘 拷贝 数据到内核pagecache。
read返回,从内核态 切换 到用户态,CPU从pagecache 拷贝 数据到用户缓冲区。
send,可以看作write。
write系统调用,从用户态到内核态切换,CPU从用户缓冲区拷贝数据到内核socket缓冲区
然后CPU从内核socket缓冲区拷贝数据到网卡上
最后write返回,从内核态 切换 到用户态。
当然可以使用DMA技术,替代CPU在IO外设与内核缓冲区之间的拷贝。因为DMA仅仅只能用于设备之间交换数据时的数据拷贝,内存之间的数据拷贝用不了DMA。
这样优化下来会发生2次CPU数据拷贝+2次DMA数据拷贝+4次上下文切换,接下来的讲解都是基于这个成本来的。
想要提高性能就需要减少上下文切换和CPU拷贝的次数。

零拷贝技术

零拷贝是一种高效的数据传输机制,在追求低延迟的传输场景中经常使用,具体思想是计算机执行操作时,CPU不需要将数据从某处内存复制到另外一个特定区域。
现存的比较常用的零拷贝方法有下面几个:

  • sendfile
  • mmap + write
  • splice
  • Direct I/O
    不同的技术使用的场景也是不同的,使用时请结合业务逻辑。

sendfile

应用场景:用户从磁盘读取文件数据后不需要经过CPU计算/处理就直接通过网络传输出去
典型应用:MQ
Linux版本:2.1

ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
// out_fd:目的端文件描述符
// in_fd:源端文件描述符
// offset:源端偏移量
// count:数据长度
// 返回值:实际复制数据的长度

我们只需要传递文件描述符就可以代替数据的拷贝了,直接替代read+write操作。sendfile一次系统调用就相当于之前的两次系统调用。这是因为page cache和socket buffer均在内核空间,sendfile直接把内核缓冲区数据拷贝到socket缓冲区上了,直接省略掉用户态。
成本:1次系统调用,2次上下文切换,1次CPU数据拷贝,2次DMA数据拷贝

sendfile + SG-DMA

Linux版本:2.4
如果网卡支持SG-DMA(The Scatter-Gather Direct Memory Access)技术,可以直接将内核态缓冲区数据直接SG-DMA到网卡上,省略了内核态缓冲区->socket缓冲区->网卡的步骤。
成本:1次系统调用,2次上下文切换,1次DMA数据拷贝,1次SG-DMA数据拷贝
这就是真正的zero-copy,完全没有通过内存层面去拷贝数据,全程使用DMA传输。
局限性:当然sendfile也是有局限性的,它直接隔离了应用程序对数据操作,如果需要从数据中提取统计信息或者进行加解密,sendfile根本使用不了。

mmap + write

mmap:memory map,一种内存映射文件的方法。即将一个文件或者其他对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址直接对映。这样进程就可以采用指针的方式直接读写操作这一块内存,系统自动回写脏页到对应的文件磁盘上。这样对文件操作就不需要调用read+write了。并且内核空间对这段区域的修改也直接反映在了用户空间,从而实现不同进程间的文件共享。

mmap技术特点如下:
1、用户空间的mmap file使用虚拟内存,实际上不占有物理内存,只有内核空间的kernel buffer cache才占据实际物理内存
2、mmap需要配合write
3、mmap仅仅避免内核空间到用户空间的CPU数据包被,但是内核空间内部还是需要CPU负责数据拷贝
使用mmap流程如下:
1、用户调用mmap,从用户态切换到内核态,将内核缓冲区映射到用户缓存区
2、DMA控制器将数据从磁盘拷贝到内核缓冲区
3、mmap返回,从内核态切换到用户态
4、用户进程调用write,尝试把文件数据写到内核socket buffer中,从用户态切换到内核态
5、CPU将内核缓冲区数据拷贝到socket buffer
6、DMA控制器将数据从socket buffer拷贝到网卡
7、write返回
成本:2次系统调用、4次上下文切换、1次CPU数据拷贝、2次DMA数据拷贝
应用场景
1、多个线程以只读方式同时访问一个文件,mmap机制下的多线程共享同一个物理内存空间,节约了内存。
例子:多个进程可以依赖于同一个动态链接库,利用mmap可以实现内存仅仅加载一份动态链接库,多个进程共享此库
2、mmap可用于进程间通信,对于同一个文件对应的mmap分配的物理内存天然多线程共享,可以依赖于操作系统的同步原语
3、mmap比sendfile多了一次CPU参与的内存拷贝,但是用户空间与内核空间之间不需要数据拷贝,所以效率也很高

splice

Linux版本:2.6.17

#include <fcntl.h>
ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);

splice用于在两个文件描述符之间移动数据, 也是零拷贝。
fd_in参数是待输入描述符。如果它是一个管道文件描述符,则off_in必须设置为NULL;否则off_in表示从输入数据流的何处开始读取,此时若为NULL,则从输入数据流的当前偏移位置读入。

fd_out/off_out与上述相同,不过是用于输出。

len参数指定移动数据的长度。

flags参数则控制数据如何移动:

SPLICE_F_NONBLOCK:splice 操作不会被阻塞。然而,如果文件描述符没有被设置为不可被阻塞方式的 I/O ,那么调用 splice 有可能仍然被阻塞。
SPLICE_F_MORE:告知操作系统内核下一个 splice 系统调用将会有更多的数据传来。
SPLICE_F_MOVE:如果输出是文件,这个值则会使得操作系统内核尝试从输入管道缓冲区直接将数据读入到输出地址空间,这个数据传输过程没有任何数据拷贝操作发生。
2. 使用splice时, fd_in和fd_out中必须至少有一个是管道文件描述符。

调用成功时返回移动的字节数量;它可能返回0,表示没有数据需要移动,这通常发生在从管道中读数据时而该管道没有被写入的时候。

失败时返回-1,并设置errno

splice系统调用直接在内核空间的read buffer 和socket buffer之间建立了管道,避免了用户缓冲区和socket buffer之间的CPU拷贝
成本:1次splice系统调用、1次pipe调用、2次上下文切换、2次DMA数据拷贝
局限性
1、用户程序不能对数据进行操作,与sendfile类似
2、Linux管道缓冲机制,可以用于任意两个文件描述符中传输数据,但是其中一个必须是管道设备

Direct I/O

缓存文件I/O:用户空间要读取一个文件并不是直接与磁盘进行交互看,而是中间夹了一层缓存,即page cache
直接文件I/O:用户空间读取文件直接与磁盘交互,数据直接存储在用户空间中,没有中间page cache曾,绕过了内核。
部分操作系统中,在直接文件I/O模式下,write虽然能够保证文件数据落盘,但是文件元数据不一定落盘,所以还需要执行一次fsync操作。
局限性
1、设备之间数据传输通过DMA,所以用户空间的数据缓冲区内存页必须进行页锁定,这是为了防止其物理页地址被交换到磁盘或者被移动到新的地址导致DMA去拷贝数据时在指定地址找不到内存页从而引发缺页异常,而页锁定的开销也不小,所以应用程序必须分配和注册一个持久的内存池,用户数据缓冲。(应用程序手动做缓存池)
2、如果在应用程序的缓存中没有找到,那么就直接从磁盘加载,十分缓慢
3、应用层引入缓存管理以及底层硬件管理(页锁定),很麻烦

经典应用

在之前的笔记中有谈到kafka高性能的原因之一就是使用了zero-copy:消息队列重要机制讲解以及MQ设计思路(kafka、rabbitmq、rocketmq,这里稍微拓展一下:
生产者发消息给kafka,kafka将消息持久化落盘。
消费者从kafka拉取消息,kafka从磁盘读取一批数据,通过网卡发送。
接收消息持久化的时候使用到了mmap机制,对接收的数据持久化。发送消息的时候使用sendfile从持久化介质中读取数据然后对外发送。
sendfile避免了内核空间到用户空间的CPU数据拷贝,同时sendfile基于page cache实现,如果有多个消费者同时消费一个topic消息,消息会在page cache上缓存,就只需要一次磁盘IO了。
所以我们应该熟悉掌握sendfile 和 mmap

零拷贝机制在文件传输中的使用手法相关推荐

  1. 浅析操作系统和Netty中的零拷贝机制

    点击关注公众号,Java干货及时送达 零拷贝机制(Zero-Copy)是在操作数据时不需要将数据从一块内存区域复制到另一块内存区域的技术,这样就避免了内存的拷贝,使得可以提高CPU的.零拷贝机制是一种 ...

  2. 零拷贝、如何实现零拷贝、大文件如何传输

    9.零拷贝 9.1.为什么要有DMA技术? 1.在没有 DMA 技术前,I/O 的过程: CPU 发出对应的指令给磁盘控制器,然后返回: 磁盘控制器收到指令后,于是就开始准备数据,会把数据放⼊到磁盘控 ...

  3. linux I/O--IO原理和几种零拷贝机制(五)

    前言 零拷贝(Zero-copy)技术指在计算机执行操作时,CPU 不需要先将数据从一个内存区域复制到另一个内存区域,从而可以减少上下文切换以及 CPU 的拷贝时间.它的作用是在数据报从网络设备到用户 ...

  4. 深入剖析Linux IO原理和几种零拷贝机制的实现

    本文来说下Linux IO原理和几种零拷贝机制的实现 文章目录 概述 物理内存和虚拟内存 物理内存 虚拟内存 内核空间和用户空间 内核空间 用户空间 Linux的内部层级结构 Linux I/O读写方 ...

  5. Linux IO原理和零拷贝机制

    目录 1 概述 2 Linux I/O读写方式 2.1 I/O中断原理 2.2. DMA传输原理 2.3 传统I/O方式 3 零拷贝方式 3.1 用户态直接I/O 3.2 mmap + write 3 ...

  6. 什么是零拷贝机制(Zero Copy) ?

    要理解零拷贝机制,首先需要了解它所要解决的问题,试想一个场景:我们需要从磁盘读取一个文件通过网络输出到一个客户端. 服务端的步骤一般是这样的: read(file, tmp_buf, len); wr ...

  7. 零拷贝机制(Zero Copy)

    要理解零拷贝机制,首先需要了解它所要解决的问题,试想一个场景:我们需要从磁盘读取一个文件通过网络输出到一个客户端. 服务端的步骤一般是这样的: read(file, tmp_buf, len); wr ...

  8. 文件服务器恢复测试,基于文件传输中文件损坏检测和恢复办法.doc

    基于文件传输中文件损坏检测和恢复办法 基于文件传输中文件损坏检测和恢复办法 摘 要:在网络上文件传输是一种常见的应用,讨论在文件传输完成后检测错误和恢复数据的办法. 关键词:文件传输;文件校验;恢复 ...

  9. 使用ADB Pull文件传输中卡住的解决方法

    使用ADB Pull文件传输中卡住的解决方法 原因分析: 尝试的方法 最终解决方法 优化方法 原因分析: 硬件:PCIE转USB3.0(无供电),PC到手机延长线15M. 使用同一ADB.exe程序在 ...

最新文章

  1. 巨潮网怎么下载年报_上海注册公司后如何下载电子营业执照
  2. php上下翻页,一个很不错的PHP翻页类
  3. 由作用域安全的构造函数想到的
  4. linux 15秒 搭建VSFTPD文件服务器
  5. php获取laydate,laydate日历控件使用方法实例分享
  6. 竹林蹊径:深入浅出Windows驱动开发
  7. ubuntu 时区 修改时间 保存 重启 变化等
  8. oracle卸载客户端,oracle11g客户端如何完全卸载
  9. 微信小程序服务通知开发
  10. c++实数运算和整数运算。
  11. 互联网大厂裁掉你的奇葩理由
  12. 搭建机器人电控系统——通信协议——IIC通信原理及其实例(库函数+模拟IO口)
  13. 软件测试面试英文自我介绍,软件测试英文面试自我介绍范文
  14. Mysql引擎·索引·事务·锁机制·优化推荐
  15. 给Android手机设置的壁纸应该是多大尺寸
  16. Java错误类型:Exception in thread main java.lang.Error: Unresolved compilation problem: Syntax error,
  17. 禁用Web服务器the TRACE and TRACK methods,修复80端口httpd漏洞:CVE-2003-1567
  18. C++函数模板与类模板的区别
  19. Chart.js入门:简介
  20. git提示please tell me who you are

热门文章

  1. matlab 次坐标轴 标注,matlab标注坐标轴
  2. Linux怎么更改声音板卡顺序,51CTO博客-专业IT技术博客创作平台-技术成就梦想
  3. ccxt k线数据_寻找相似的历史k线
  4. step7db块寻址_step7中的难点:间接寻址示例,中文详细注释。
  5. Vuejs开发环境搭建及热更新
  6. 关于DJANGO MODELS的个人理解和RELATED_NAME的使用
  7. 站长工具--IP地址库
  8. asp.net mvc 如何在View中获取Url参数的值
  9. Visual Studio 配色方案
  10. 一 MVC - HtmlHelper