零拷贝(zero-copy)
名词介绍
- buffer : buffer cache 的内存,是块设备的读写缓冲区,靠近存储设备,或者是disk的缓冲区
- cache: page cache 的内存, 文件系统的cache,是memory的缓冲区
- Page cache(页面缓存):页缓冲或文件缓冲,是由好几个磁盘块构成,大小通常为4k,在64位系统上为8k,构成的几个磁盘块在物理磁盘上不一定连续,文件的组织单位为一页, 也就是一个page cache大小,文件读取是由外存上不连续的几个磁盘块,到buffer cache,然后组成page cache,然后供给应用程序
- Buffer cache(块缓存):块缓冲,是对物理磁盘上的一个磁盘块进行的缓冲,其大小为通常为1k,磁盘块也是磁盘的组织单位。
设立buffer cache的目的是为在程序多次访问同一磁盘块时,减少访问时间。系统将磁盘块首先读入buffer cache,如果cache空间不够时,会通过一定的策略将一些过时或多次未被访问的buffer cache清空。程序在下一次访问磁盘时首先查看是否在buffer cache找到所需块,命中可减少访问磁盘时间。不命中时需重新读入buffer cache。对buffer cache的写分为两种,一是直接写,这是程序在写buffer cache后也写磁盘,要读时从buffer cache上读,二是后台写,程序在写完buffer cache后并不立即写磁盘,因为有可能程序在很短时间内又需要写文件,如果直接写,就需多次写磁盘了。这样效率很低,而是过一段时间后由后台写,减少了多次访磁盘的时间
Buffer cache是由物理内存分配,Linux系统为提高内存使用率,会将空闲内存全分给buffer cache ,当其他程序需要更多内存时,系统会减少cache大小
- DMA:Direct Memory Access 直接内存访问,允许不同速度的硬件之间直接交互,而不需要占用CPU的中断负载,网卡,显卡,磁盘驱动,声卡等常见设备都支持
- 零拷贝(Zero-copy):没有 CPU 拷贝时间
Page cache 和 buffer cache 的区别
- Page cache在linux读写文件时,它用于缓存文件的逻辑内容,从而加快对磁盘上映像和数据的访问。具体说是加速对文件内容的访问,buffer cache缓存文件的具体内容——物理磁盘上的磁盘块,这是加速对磁盘的访问
- 磁盘的操作有逻辑级(文件系统)和物理级(磁盘块),这两种Cache就是分别缓存逻辑和物理级数据的
- 如果要通过文件系统操作文件,那么文件将被缓存到Page Cache,如果需要刷新文件的时候,Page Cache将交给Buffer Cache去完成,因为Buffer Cache就是缓存磁盘块的。即直接去操作文件,那就是Page Cache区缓存,用dd等命令直接操作磁盘块,就是Buffer Cache缓存
零拷贝:sendfile,mmap,splice,直接 Direct I/O
- 使用 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
零拷贝是网络编程的关键
java常用的零拷贝 mmap 内存映射和 sendFile
DMA:直接内存拷贝 不使用CPU
传统IO:
File.read(file, buf, len);
Socket.send(socket, buf, len);
DMA将数据从硬盘拷贝到内核态
CPU拷贝将数据从内核态到用户态 修改完 CPU到socket DMA到 ->协议栈
4次拷贝 3次切换 如果最后一次调用 write 结束切换回用户态也算就是 4次切换
mmap优化
mmap通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据。减少网络传输时内核空间到用户空间的拷贝次数
DMA将数据从硬盘拷贝到内核态
内核buffer和用户buffer共享
CPU拷贝将数据从内核态到socket buffer
socket buffer DMA拷贝到协议栈
3次拷贝3次切换
sendFile优化 2.1
linux提供该函数
原理:数据不经过用户态,直接从内核缓冲区进入到Socket Buffer,同时由于和用户态无关,还减少了一次上下文切换
3次拷贝,2次切换
零拷贝是没有cpu拷贝
linux 2.4 sendFile
避免从内核缓冲区拷贝到Socket buffer的操作而直接拷贝到协议栈
2次拷贝 2次切换
mmap适合小数据量读写(如32位系统,内存映射地址有4GBÿ