{ Zero-Copy }

  • Zero-Copy

    |

    Linux Zero-Copy

    什么是零拷贝 ?

    Zero Copy 是一种避免 CPU 将数据从一块存储拷贝到另一块存储的技术。 Zero Copy 可以减少数据拷贝和共享总线操作的次数,消除传输数据再存储器之间不必要的拷贝次数,从而有效地提高数据传输地效率。

    Linux IO Copy

    • read() && write()

    当我们在访问一个网页的时候,在 Web Server (Linux) 会调用一下两个 文件读写函数:

    1
    2
    read(fd, buffer, len);
    write(sockfd, buffer, len);

    过程分析:

    1. 调用 read(),将具体的磁盘文件数据读取到 内核(kernel)的文件系统缓冲区中

    2. 接着是将 内核缓存区的数据 拷贝到 用户的缓冲区中

    3. 调用 write(),将用户缓冲区的数据写入到 内核 socket 的发送缓存区中

    4. 在 write() 返回后,内核会将 socket 发送区的数据拷贝到 网卡驱动中

    性能分析

    这个过程中,一共发生了四次 I/O copy, 这期间数据按照 kernel -> user -> kernel -> hard drive 的路线,在 内核用户 白白消耗了一圈的 性能开销,同时除了考虑 I/O 的性能开销,还要考虑系统 context switch 带来的开销,当系统调用 read() 时,系统会从 用户态 切换到 内核态,当 read() 返回时,又需要将 内核态 切换到 用户态,同理,write() 也会导致两次的 context switch,也就是说 read() 和 write() 总共会导致 4次的 I/O copy 和 4次上下文切换。

    • sendfile()

      而采用 sendfile()可减少在 read() & write() 所产生的多次 I/O 拷贝和 context switch

    1
    sendfile(sockfd, fd, NULL, len);

    过程分析:

    1. 将磁盘中的文件数据拷贝到 内核中的文件缓冲区

    2. 向 socket buffer 中 追加 当前的数据在 kernel buffer 中的位置和偏移量

    3. 根据 socket buffer 中的位置和偏移量,将 kernel buffer 中的数据 copy 到 网卡驱动中

    性能分析:

    这次过程中,sendfile() 相比于 read() & write() ,对于将要发送的数据 (socket) ,采用的是记录下对应的 数据在 kernel buffer 中的 位置和偏移量,在最后要发送 socket buffer的数据到网卡设备时,只需通过 位置及偏移量 找到对应 kernel buffer的数据。相比于 read / write, 少了两次 I/O copy,和两次 context switch,性能有了很大的提升。

    总结

    为什么说是 zero-copy 呢? 因为在 sendfile() 调用的过程中,对于内核 kernel ,整个过程中是零拷贝的,不涉及 内核到用户之间的数据拷贝。