@ -342,6 +342,88 @@ epoll支持水平触发和边缘触发, 最大的特点在于边缘触发, 它
## 零拷贝(Zero-Copy)
### 数据的四次拷贝与四次上下文切换
很多应用程序在面临客户端请求时,可以等价为进行如下的系统调用:
- File.read(file, buf, len);
- Socket.send(socket, buf, len);
例如消息中间件 Kafka 就是这个应用场景, 从磁盘中读取一批消息后原封不动地写入网卡( NIC, Network interface controller) 进行发送。在没有任何优化技术使用的背景下, 操作系统为此会进行 4 次数据拷贝,以及 4 次上下文切换,如下图所示:
![Zero-Copy ](images/OS/Zero-Copy.png )
如果没有优化,读取磁盘数据,再通过网卡传输的场景性能比较差:
**4次copy**
- CPU 负责将数据从磁盘搬运到内核空间的 Page Cache 中
- CPU 负责将数据从内核空间的 Socket 缓冲区搬运到的网络中
- CPU 负责将数据从内核空间的 Page Cache 搬运到用户空间的缓冲区
- CPU 负责将数据从用户空间的缓冲区搬运到内核空间的 Socket 缓冲区中
**4次上下文切换**
- read 系统调用时:用户态切换到内核态
- read 系统调用完毕:内核态切换回用户态
- write 系统调用时:用户态切换到内核态
- write 系统调用完毕:内核态切换回用户态
**问题分析**
- CPU 全程负责内存内的数据拷贝还可以接受,因为效率还算可以接受,但是如果要全程负责内存与磁盘、网络的数据拷贝,这将难以接受,因为磁盘、网卡的速度远小于内存,内存又远远小于 CPU
- 4 次 copy 太多了, 4 次上下文切换也太频繁了
### 零拷贝技术
零拷贝技术是一个思想, 指的是指计算机执行操作时, CPU 不需要先将数据从某处内存复制到另一个特定区域。
可见,零拷贝的特点是 CPU 不全程负责内存中的数据写入其他组件, CPU 仅仅起到管理的作用。但注意,零拷贝不是不进行拷贝,而是 CPU 不再全程负责数据拷贝时的搬运工作。如果数据本身不在内存中,那么必须先通过某种方式拷贝到内存中(这个过程 CPU 可以不参与),因为数据只有在内存中,才能被转移,才能被 CPU 直接读取计算。
零拷贝技术的具体实现方式有很多,例如:
- **sendfile**
- **mmap**
- **splice**
- ** 直接 Direct I/O**
不同的零拷贝技术适用于不同的应用场景,下面依次进行 sendfile、mmap、Direct I/O 的分析。
- DMA 技术回顾: DMA 负责内存与其他组件之间的数据拷贝, CPU 仅需负责管理,而无需负责全程的数据拷贝;
- 使用 page cache 的 zero copy:
- sendfile: 一次代替 read/write 系统调用,通过使用 DMA 技术以及传递文件描述符,实现了 zero copy
- mmap: 仅代替 read 系统调用, 将内核空间地址映射为用户空间地址, write 操作直接作用于内核空间。通过 DMA 技术以及地址映射技术,用户空间与内核空间无须数据拷贝,实现了 zero copy
- 不使用 page cache 的 Direct I/O: 读写操作直接在磁盘上进行, 不使用 page cache 机制,通常结合用户空间的用户缓存使用。通过 DMA 技术直接与磁盘/网卡进行数据交互,实现了 zero copy
#### sendfile
snedfile 的应用场景是用户从磁盘读取一些文件数据后不需要经过任何计算与处理就通过网络传输出去。此场景的典型应用是消息队列。在传统 I/O 下,上述应用场景的一次数据传输需要四次 CPU 全权负责的拷贝与四次上下文切换。sendfile 主要使用到了两个技术:
- DMA 技术
- 传递文件描述符代替数据拷贝
**利用DMA技术**
sendfile 依赖于 DMA 技术,将四次 CPU 全程负责的拷贝与四次上下文切换减少到两次,如下图所示:
![利用DMA技术 ](images/OS/利用DMA技术.png )
利用 DMA 技术减少 2 次 CPU 全程参与的拷贝DMA 负责磁盘到内核空间中的 Page cache( read buffer) 的数据拷贝以及从内核空间中的 socket buffer 到网卡的数据拷贝。
https://blog.csdn.net/weixin_38726452/article/details/120168360
https://mp.weixin.qq.com/s?__biz=Mzg4MDAxNzkyMw==& mid=2247489694& idx=1& sn=3c9f532eb9d650b2ae2b1db5d0c91b09& chksm=cf7acff2f80d46e431c0bd0d60270a8ce3d31af8a50678e11d5b39bb6c8a9dfa333e7ac56704& mpshare=1& scene=23& srcid=0903RuYh2ynm5j60Y7QtETJO& sharer_sharetime=1638369376739& sharer_shareid=0f9991a2eb945ab493c13ed9bfb8bf4b%23rd
## BIO(同步阻塞I/O)
每个客户端的Socket连接请求, 服务端都会对应有个处理线程与之对应, 对于没有分配到处理线程的连接就会被阻塞或者拒绝。相当于是`一个连接一个线程`。