零拷贝详解:mmap、sendfile 与 splice
传统文件发送常先把磁盘数据读入内核页缓存,再复制到用户缓冲,随后写回 Socket 缓冲,最后由设备传输。零拷贝不是承诺完全没有物理搬运,而是尽量避免 CPU 在用户态与内核态之间复制同一批数据。
mmap 把文件页映射到进程地址空间,应用可直接访问页缓存,省去 read 到用户缓冲的一次复制,但首次访问可能缺页,映射生命周期、截断和一致性需要谨慎处理。sendfile 让内核直接把文件描述符的数据送往 Socket,适合应用不需要修改内容的静态传输。支持页引用或 DMA 聚合时,还可进一步减少内核缓冲间复制。
splice 在支持的文件描述符之间借助管道移动或引用页,适合构建内核内数据通路。不同操作系统、文件系统、设备与加密路径支持程度不同;TLS 若在用户态处理,数据仍可能需要进入用户空间,内核 TLS 或硬件卸载则是另一套权衡。
收益取决于数据大小和是否需要变换。小数据可能被系统调用与映射管理开销抵消;压缩、解析、加密或修改内容时,用户态缓冲仍有必要。评估应测 CPU 使用、吞吐、延迟和上下文切换,而非只数理论复制次数。
误区是把零拷贝理解为磁盘到网卡没有任何复制、认为 mmap 永远快、忽略错误与短写、以及对所有请求盲目使用。小结:零拷贝优化数据路径,适合大块透传;先画清数据经过哪些缓冲,再判断哪次搬运可以安全省略。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Dai Wei!
评论

