零拷贝-高效的数据传输方式

假设这样的情景:从磁盘读取数据,然后经过应用程序,使用Socket编程,将数据通过应用程序传输出去。这个时候,应用程序在执行最底层的操作时,是调用系统内核来完成任务的。零拷贝就是系统内核直接从磁盘获取数据,然后将数据发送出去,绕过了应用程序。这种方式必然是高效的。因为它比传统的方式少走了好几步路。

当程序调用内核操作时,处于内核的上下文环境中,当程序调用用户代码的时候,处于用户模式的上下文环境中。每一次从内核的上下文切换到用户的上下文,都需要消耗资源。

Java的类库java.nio.channels.FileChannel类的transferTo()方法,支持Liunx和Unix系统上的零拷贝。这个方法直接从调用它的通道传输到另一个可写字节通道。不需要流经应用程序。

1 传统的方法

代码类似于:

File.read(fileDesc,buf,len);

Socket.send(socket,buf,len);

下图显示了方法调用的过程

下图是上下文切换的过程

1 read()调用,导致从用户模式切换到内核模式。内核发出sys_read()(或者其他等的方法)从文件中读取数据。在方法调用的过程中,由直接内存访问(DMA)访问,从磁盘读取文件内容并将其存储到内核地址空间的缓冲区中。

2 请求的数据从读缓冲区复制到用户的缓冲区,read()方法返回调用。调用返回会导致从内核模式切换到用户模式。数据存储在用户地址空间的缓冲区中。

3 send()调用导致从用户模式切换到内存模式。数据从用户地址空间的缓冲区复制到内核地址空间缓冲区。(这个缓冲区和步骤以的缓冲区是不一样的,这个是与目标Socket相关联的缓冲区)。

4 send()返回调用。由内核模式切换到用户模式,当DMA引擎将数据从内环缓冲区传递到协议引擎的时候,发生第四次复制。

(4次复制,4次切换)

步骤一是将数据首先传输到了内核的缓冲区,(而不是将数据直接传输到用户缓冲区)似乎效率低下。但是中间内核缓冲区被引入到流程中以提高性能。使用读取端的中间缓冲区允许内核缓冲区在应用程序未请求与内核缓冲区保持的数据量相同时充当“预读缓存”。当请求的数据量小于内核缓冲区大小时,这显着提高了性能。写入端的中间缓冲区允许写入异步完成。

但是,如果请求的数据大小远大于内核缓冲区大小,则此方法本身可能会成为性能瓶颈。在最终将数据传递到应用程序之前,数据会在磁盘,内核缓冲区和用户缓冲区之间多次复制。

2 改进的传统方法(非真正的零拷贝方法)

 

实际上并不需要第二个和第三个数据副本。应用程序除了缓存数据并将其传输回Socket缓冲区之外什么都不做。相反,数据可以直接从读缓冲区传输到套接字缓冲区。该transferTo() 方法可以让您完成此操作。

public void transferTo(long position, long count, WritableByteChannel target);

 

该transferTo()方法将数据从文件通道传输到给定的可写字节通道。在内部,它取决于底层操作系统对零拷贝的支持; 在UNIX和各种版本的Linux中,此调用被路由到sendfile() 系统调用,它将数据从一个文件描述符传输到另一个文件描述符:

#include <sys/socket.h>

ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

传统方法中的file.read()和socket.send() 调用操作可以替换为单个调用transferTo(position, count, writableChannel);

 

下图使用使用zerocopy时的方法调用

这时的上下文切换为:

1 transferTo()方法,由DMA引擎将文件内容复制到读缓冲区中。然后,内核将数据复制到与输出Socket关联的内核缓冲区中。

2 DMA引擎将数据从内核Socket缓冲区传递到协议引擎。

(3次复制,2次切换)

 

3 零拷贝方法

如果底层网络接口卡支持gather操作,可以进一步减少系统消耗。在Liunx内核2.4或者更高的版本中,修改了Socket缓冲区描述符,这个特性可以支持这个操作。不仅减少了上下文的切换,还消除了需要CPU参与的复制数据副本。虽然用户在使用的时候没有区别,但是内在函数已经改变了。

1 transferTo()方法是文件内容内DMA引擎复制到内核缓冲区中。

2 没有数据被复制到Socket缓冲区中。只有具有有关数据位置和长度信息的描述符才会写到Socket缓冲区,DMA引擎将数据直接从内核缓冲区传递到协议引擎。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值