Page Cache
Page Cache以物理页为单位对磁盘文件进行缓存。对于Linux等类Unix操作系统,通常会把空闲的内存用作Page Cache,在有内存请求的时候逐步释放缓存。
应用层对文件的访问一般有两种方式:
- mmap 创建直接访问的虚拟地址空间
- read/write 寻址访问
文件通过 mmap 映射到虚拟地址空间后,对这个内存区域的第一次访问时,页表(存放逻辑页与物理页的对应关系)还没有建立,必然会出现一个内存访问的缺页错误。内核在处理时,通过页面预读函数分配内存页面,然后将对应的文件块读入。
通过系统调用 read 来访问文件时,最终也是通过页面预读函数分配 Page Cache 的。而对 Page Cache 的写操作,使用写时复制机制,等到要同步或者清理缓存的时候,再把文件同步回磁盘。
页、块与扇区
页:内核把物理页作为内存管理的基本单位。
块:内核只能基于块来访问物理文件系统,块被称为是文件系统的最小寻址单元。
扇区:块设备的基本单元,也是块设备的最小寻址单元。
页 > 块 > 扇区
Direct I/O 和 Buffered I/O
在 Buffered I/O 中,Linux 会将 I/O 的数据缓存在 Page Cache 中,数据会先被复制到内核的缓冲区,再从缓冲区复制到应用程序的用户地址空间。在没有 CPU 干预的情况下,可以通过 DMA 操作在磁盘和 Page Cache 之间直接进行数据的传输。这样做有两大优点:
- 分离了应用程序和物理设备。
- 减少 I/O 次数,提高系统性能。
Direct I/O 可以省略使用 Buffered I/O 中的内核缓冲区,数据可以直接在用户空间和磁盘之间进行传输。进程在打开文件的时候,将对文件的访问模式设置为 O_DIRECT,接下来将使用 Direct I/O方式去读写文件。其最大的优点就是减少内核缓冲区与用户空间的数据复制次数,然而不经过内核缓冲区直接进行磁盘读写,必然会引起阻塞,因此 Direct I/O 通常与 AIO(异步I/O)一起使用。
参考资料
[1] 《Linux开源存储全栈详解:从Ceph到容器存储》 英特尔亚太研发有限公司 著