NIO 与零拷贝

零拷贝介绍

  1. 零拷贝是网络编程的关键, 很多性能优化都需要零拷贝。
  2. 在 Java程序中, 常用的零拷贝方式有m(memory)map[内存映射] 和 sendFile。它们在OS中又是怎样的设计?
  3. NIO中如何使用零拷贝?

NIO 与 传统IO对比

  • 传统IO流程示意图

    NIO 与零拷贝_第1张图片

    • user context: 用户态
    • kernel context: 内核态
    • User space: 用户空间
    • Kernel space: 内核空间
    • Syscall read: 系统调用读取
    • Syscall write: 系统调用写入
    • Hard drive: 硬件驱动
    • kernel buffer: 内核态缓冲区
    • user buffer: 用户态缓冲区
    • socket buffer: 套接字缓存
    • protocol engine: 协议引擎
    • DMA: Direct Memory Access: 直接内存拷贝(不使用CPU)
    • 总结: 4次拷贝, 3次状态切换, 效率不高
  • mmap优化流程示意图

    NIO 与零拷贝_第2张图片

    • mmap 通过内存映射, 将文件映射到内核缓冲区, 同时, 用户空间可以共享内核空间的数据。
    • 这样, 在进行网络传输时, 就可以减少内核空间到用户空间的拷贝次数。
    • 总结: 3次拷贝, 3次状态切换, 不是真正意义上的零拷贝。
  • sendFile Linux2.1版本优化流程示意图

    NIO 与零拷贝_第3张图片

    • 数据根本不经过用户态, 直接从内核缓冲区进入到Socket Buffer, 同时, 由于和用户台完全无关, 就减少了一次上下文切换。
    • 但是仍然有一次CPU拷贝, 不是真正的零拷贝(没有CPU拷贝)。
    • 总结: 3次拷贝, 2次切换
  • sendFile Linux

    NIO 与零拷贝_第4张图片

    • 避免了从内核缓冲区拷贝到Socket buffer的操作, 直接拷贝到协议栈, 从而再一次减少了数据拷贝。
    • 其实是有一次cpu拷贝的, kernel buffer -> socket buffer, 但是拷贝的信息很少, length, offset, 消耗低, 基本可以忽略。
    • 总结: 2次拷贝(如果忽略消耗低的cpu拷贝的话), 2次切换, 基本可以认为是零拷贝了。

零拷贝理解

  • 零拷贝是从操作系统的角度来看的。内核缓冲区之间, 没有数据是重复的(只有kernel buffer有一份数据)。
  • 零拷贝不仅仅带来更少的数据复制, 还能带来其他的性能优势: 如更少的上下文切换, 更少的 CPU 缓存伪共享以及无CPU校验和计算。

mmap 与 sendFile 总结

  • mmap适合小数据两读写, sendFile适合大文件传输
  • mmap 需要3次上下文切换, 3次数据拷贝; sendFile 需要3次上下文切换, 最少2次数据拷贝。
  • sendFile 可以利用 DMA 方式, 减少 CPU 拷贝, 而 mmap则不能(必须从内核拷贝到Socket缓冲区)。

你可能感兴趣的:(JAVA技术)