基于zero copy的高效数据传输

简介

在学习kafka如何实现高吞吐量的时候遇到一个技术zero copy,追随kafka文档中的链接深入了解了一下zero copy,在这里mark一下,原文链接https://www.ibm.com/developerworks/linux/library/j-zerocopy/

通常的实现方式

假设这样一个场景:从文件中读取数据然后通过网络将数据发送出去,实现的核心部分一般是这样的

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

尽管实现非常简单,需要4次用户态和内核态的上线文切换,数据需要拷贝4次,整个流程如下图

基于zero copy的高效数据传输_第1张图片
Paste_Image.png
  1. read()从用户态切换到内核态,调用sys_read()从文件中读取数据,数据从disk拷贝到内核地址空间
  2. 数据从内核地址空间拷贝到用户地址空间,read函数返回
  3. send函数从用户态切换到内核态,将数据从用户地址空间拷贝到内核地址空间
  4. 数据从内核地址空间拷贝到协议引擎,send函数返回
    使用内核对数据缓存相比于用户直接读取数据好像是低效的,在某些情况下内核态的数据缓存确实会提高效率,但是当数据大小超过内核缓存的大小时,这个操作是低效的。

zero copy

其实对于这种场景下,数据没有必要从内核态拷贝到用户态,可以直接从read buffer拷贝到socket buffer,transferTo()函数就是实现这样的操作,但是transferTo函数需要操作系统的支持,在linux下sendfile实现了这样的操作,刚才的实现可以改成下面的:

transferTo(position, count, writableChannel);

这样数据就不需要从内核空间拷贝到用户空间了

基于zero copy的高效数据传输_第2张图片
Paste_Image.png

如果内核支持gather operations的话还可以进一步优化,在用户实现层面没有发生变化,优化都是在内核实现中的,首先数据从disk拷贝到内核buffer,然后并不需要把数据再次拷贝到socket buffer,只需要把数据位置和长度告诉socket buffer即可,优化之后的数据流如下:

基于zero copy的高效数据传输_第3张图片
Paste_Image.png

性能对比

基于zero copy的高效数据传输_第4张图片
Paste_Image.png

你可能感兴趣的:(基于zero copy的高效数据传输)