图解NIO零拷贝零拷贝是一种数据传输的技术,也称为零拷贝IO(Input/Output)。在零拷贝技术中,数据可以直接从
零拷贝是一种数据传输的技术,也称为零拷贝IO(Input/Output)。在零拷贝技术中,数据可以直接从一个存储设备传输到另一个存储设备,而无需在中间进行任何数据复制或拷贝操作。
基本概念介绍
- 用户态: 用户程序运行的环境,也是用户与操作系统交互的界面。在用户态中,用户程序可以访问系统资源,如文件、网络、内存等,但是不能直接访问硬件设备。用户态程序通过系统调用来请求内核提供服务,如文件读写、进程管理等。
- 内核态: 操作系统的核心部分,负责管理系统的硬件资源和提供基本的系统服务。在内核态中,操作系统可以直接访问硬件设备,并控制它们的运行。内核态具有较高的执行权限和特权级别,可以执行一些操作系统的核心功能,如进程调度、内存管理、设备驱动等。
- 上下文切换: 用户态和内核态之间通过系统调用来进行通信和交互。用户程序请求操作系统提供服务时,会通过系统调用进入内核态执行相应的操作,内核态执行完操作后再返回到用户态。这种分离的设计可以保护系统的稳定性和安全性,同时也方便了系统的管理和维护。
- 管道:Linux的管道是一种将一个命令的输出作为另一个命令的输入的机制以实现数据流的传递和处理。
- DMA: (Direct Memory Access)又称直接内存存取,也就是通过硬件直接访问主内存,不需要通过 cpu,有点像协处理器,目前大多数的硬件都支持 DMA,例如网卡、显卡、声卡、磁盘等等。
IO实现方式
普通IO
程序进行一次文件读取与发送的整体动作如下所示:
用户会对内核发送read()
和wirte()
两个指令,这会带来4次内核态与用户态之间的切换以及2次CPU的拷贝。
mmap
mmap技术是常见的NIO技术之一,RocketMQ底层使用的就是mmap。与前面提到的read()
和wirte()
相比,mmap使用mmap()
指令替代了read()
,mmap的好处是使用内存地址的映射代替了文件从内核缓冲区到用户态的CPU复制,一定程度上提升了效率。
mmap会带来4次内核态与用户态之间的切换以及1次CPU的拷贝。
sendfile
我们可以看到,mmap技术还是会带来多次的CPU复制与上下文切换,如果我们仅仅是从磁盘中读取文件,之后原封不动的输出,那么有没有更便捷高效的方式呢?sendfile就可以满足这种诉求。
sendfile只会有一次sendfile()
指令的调用,Kafka采用的就是这种方式,有2次内核态与用户态之间的切换以及1次CPU的拷贝。
splice
还有一种NIO的实现方式为splice,splice 系统调用在内核缓冲区和 socket 缓冲区之间建立管道来传输数据,避免了两者之间的 CPU 拷贝操作。
小结
总结几种IO方式如下:
IO方式 | CPU拷贝次数 | 上下文切换次数 |
---|---|---|
传统IO | 2 | 4 |
mmap | 1 | 4 |
sendfile | 1 | 2 |
splice | 0 | 2 |
转载自:https://juejin.cn/post/7411355962584399923