传统 IO
传统 IO 执行的话需要 4 次上下文切换(用户态 -> 内核态 -> 用户态 -> 内核态 -> 用户态)和 4 次拷贝(磁盘文件 DMA 拷贝到内核缓冲区,内核缓冲区 CPU 拷贝到用户缓冲区,用户缓冲区 CPU 拷贝到 Socket 缓冲区,Socket 缓冲区 DMA 拷贝到协议引擎)。
mmap
mmap 将磁盘文件映射到内存,支持读和写,对内存的操作会反映在磁盘文件上,适合小数据量读写,需要 4 次上下文切换(用户态 -> 内核态 -> 用户态 -> 内核态 -> 用户态)和3 次拷贝(磁盘文件DMA拷贝到内核缓冲区,内核缓冲区 CPU 拷贝到 Socket 缓冲区,Socket 缓冲区 DMA 拷贝到协议引擎)。
RocketMQ 中就是使用的 mmap 来提升磁盘文件的读写性能。
sendfile
sendfile+DMA scatter/gather实现的零拷贝
sendfile 是将读到内核空间的数据,转到 socket buffer,进行网络发送,适合大文件传输,只需要 2 次上下文切换(用户态 -> 内核态 -> 用户态)和 2 次拷贝(磁盘文件 DMA 拷贝到内核缓冲区,内核缓冲区 DMA 拷贝到协议引擎)。
Kafka 和 Tomcat 内部使用就是 sendFile 这种零拷贝。
总结:
1.传统I/O
硬盘—>内核缓冲区—>用户缓冲区—>内核socket缓冲区—>协议引擎
2.sendfile
硬盘—>内核缓冲区—>内核socket缓冲区—>协议引擎
3.sendfile( DMA 收集拷贝)
硬盘—>内核缓冲区—>协议引擎
网友评论