文章目录
- 0. 文件系统的层次结构
- 1.什么是page cache
- 2.感观认识page cache
- 3. Page Cache的优缺点
- 3.1 Page Cache 的优势
- 3.2 Page Cache 的劣势
0. 文件系统的层次结构
在了解page cache之前,我们先看下文件系统的层次结构。
1 VFS 层
VFS ( Virtual File System 、Virtual FileSystem Switch )层是 Linux 针对文件概念封装的一层通用逻辑,它做的事情其实非常简单,就是把所有文件系统的共性的东西抽象出来,比如 file ,inode ,dentry 等结构体,针对这些结构体抽象出通用的 api 接口,然后具体的文件系统则只需要按照接口去实现这些接口即可,在 IO 下来的时候,VFS 层使用到文件所在的文件系统的对应接口。
它的作用:为上层抽象统一的操作界面,在 IO 路径上切换不同的文件系统。
假设现在你想要写个内核文件系统,那么只需要按照 Linux 预设的一些 api 接口,实现起来就行了。
2 文件系统
VFS 把 IO 给到具体的文件系统,文件系统主要做啥呢?
它的作用:对上抽象一个文件的概念,把数据按照策略存储到块设备上。
文件系统管理的是一个线性的空间(分区,块设备),而用户看到的却是文件的概念,这一层的转化就是文件系统来做的。它负责把用户的数据按照自己制定的规则存储到块设备上。比如是按照 4K 切块存,还是按照 1M 切块存储,这些都是文件系统自己说了算。
它这一层就是做了一层空间的映射转化,文件的虚拟空间到实际线性设备的映射。 这层映射最关键的是 address_space 相关的接口来做。
3 块层
块层其实在真实的硬件之上又抽象了一层,屏蔽不同的硬件驱动,块设备看起来就是一个线性空间而已。块层主要还是 IO 调度策略的实现,尽可能收集批量 IO 聚合下发,让 IO 尽可能的顺序,合并 IO 请求减少 IO 次数等等;
划重点:块层主要做的是 IO 调度策略的一些优化。比如最出名的电梯算法就是在这里。
因为所有的 IO 都会汇聚下来,那么在块层做调度优化是最合适的。Linux 也允许用户自行配置这里的调度策略,比如 CFQ,Deadline,NOOP 等策略。
4 SCSI 层
SCSI 层这个就不用多说了,这个就是硬件的驱动而已,本质就是个翻译器。SCSI 层里面按照细分又会细分多层出来。它是给你的磁盘做最后一道程序,SCSI 层负责和磁盘硬件做转换,IO 交给它就能顺利的到达磁盘硬件。
1.什么是page cache
文件一般存放在硬盘(机械硬盘或固态硬盘)中,CPU 并不能直接访问硬盘中的数据,而是需要先将硬盘中的数据读入到内存中,然后才能被 CPU 访问。
由于读写硬盘的速度比读写内存要慢很多(DDR4 内存读写速度是机械硬盘500倍,是固态硬盘的200倍),所以为了避免每次读写文件时,都需要对硬盘进行读写操作,Linux 内核使用 页缓存(Page Cache) 机制来对文件中的数据进行缓存,即将文件中的数据缓存到page中,这些page就叫page cache。
页面缓存(Page Cache)是操作系统中的一种内存管理机制,用于缓存磁盘上的文件数据。它是在内核中维护的一部分内存,并将最近读取或写入的文件数据缓存在内存中,以提高文件访问的性能。
当应用程序需要读取文件时,内核会首先检查页面缓存中是否已经包含了所需的数据。如果数据已经在页面缓存中,则可以直接从内存中返回给应用程序,避免了频繁的磁盘访问。如果数据不在页面缓存中,则内核将从磁盘中读取数据到页面缓存,并返回给应用程序。
类似地,当应用程序写入文件时,数据会被写入页面缓存中,并由内核定期将缓存中的数据刷新回磁盘。
页面缓存的存在使得文件的读取和写入变得更加高效,因为内存的访问速度远远快于磁盘的访问速度。通过减少对磁盘的实际访问次数,页面缓存可以大大提升文件系统的性能,特别是在频繁读取相同文件或重复访问某些部分的情况下。
需要注意的是,页面缓存只是一种缓存机制,它并不提供数据持久性。文件数据仍然是存储在磁盘上的,而页面缓存只是磁盘数据的临时副本,可以被更新或替换。因此,在进行文件操作时,需要确保及时将数据刷新回磁盘,以确保数据的持久性和一致性。
额外扩展:
IO可分为缓存io和直接io,直接io跨过了page cache直接操作磁盘。
内核中的缓冲 I/O(Buffer I/O)和直接 I/O(Direct I/O)是用于实现磁盘数据读写的两种不同方式。
- 缓冲 I/O(Buffer I/O):
- 缓冲 I/O 是指在进行磁盘读写时,数据会首先被缓存在操作系统内核的页缓存中。当进行读取操作时,数据会从磁盘读取到内核页缓存中,然后再从内核页缓存复制到应用程序的缓冲区中;而在进行写入操作时,数据会被先写入内核页缓存中,由操作系统负责定期将缓存中的数据刷新至磁盘。
- 优点:利用了系统内存进行缓存,可以减少对磁盘的频繁读写,提高了访问速度。
- 缺点:需要额外的内存开销来维护缓存,同时存在数据一致性的问题,因为数据首先写入到缓存中并非直接写入到磁盘,如果系统崩溃可能会导致数据丢失或不一致。
- 直接 I/O(Direct I/O):
- 直接 I/O 是指数据在进行磁盘读写时,绕过系统内核的页缓存,直接在用户空间和磁盘之间进行数据传输。在进行读取操作时,数据直接从磁盘读取到应用程序的缓冲区中;在进行写入操作时,数据也直接从应用程序的缓冲区写入到磁盘中,而不经过内核页缓存。
- 优点:避免了数据在内核缓存中的多次拷贝,减少了内存开销,并且可以提供更加可控的数据一致性。
- 缺点:由于绕过了内核的缓存,直接 I/O 的效率受到了磁盘的物理特性限制,可能会降低读写性能。
上图中,红色部分为 Page Cache。可见 Page Cache 的本质是由 Linux 内核管理的内存区域。我们通过 mmap 以及 buffered I/O 将文件读取到内存空间实际上都是读取到 Page Cache 中。
2.感观认识page cache
通过读取 /proc/meminfo
文件,能够实时获取系统内存情况:
$ cat /proc/meminfo
...
Buffers: 1224 kB
Cached: 111472 kB
SwapCached: 36364 kB
Active: 6224232 kB
Inactive: 979432 kB
Active(anon): 6173036 kB
Inactive(anon): 927932 kB
Active(file): 51196 kB
Inactive(file): 51500 kB
...
Shmem: 10000 kB
...
SReclaimable: 43532 kB
...
根据上面的数据,你可以简单得出这样的公式(等式两边之和都是 112696 KB):
Buffers + Cached + SwapCached = Active(file) + Inactive(file) + Shmem + SwapCached
两边等式都是 Page Cache,即:
Page Cache = Buffers + Cached + SwapCached
公式推出来的
Cached + Buffers = Active(file) + Inactive(file) + Shmem;
可以看到page cache大体上分成了三大块:
- cached
- buffers
- swap cache
Cache 用于缓存文件的页数据,buffer用于缓存块设备(如磁盘)的块数据。页是逻辑上的概念,因此 Cache 是与文件系统同级的;块是物理上的概念,因此 buffer是与块设备驱动程序同级的。直白讲,buffer面向底层的磁盘IO,cache面向文件系统IO。
cache除了包括缓存文件数据页,还包括了tmpfs和shmem,居然还包括共享内存确实费解,包括tmpfs可以理解。
另一方面,并不是所有 page 都被组织为 Page Cache。
Linux 系统上供用户可访问的内存分为两个类型,即:
- File-backed pages:文件备份页也就是 Page Cache 中的 page,对应于磁盘上的若干数据块;对于这些页最大的问题是脏页回盘;
- Anonymous pages:匿名页面是指没有对应磁盘上持久化数据的页面,通常用于存储进程的堆栈、堆等动态分配的内存空间。这些页面的内容通常是程序运行时动态产生的数据,不需要持久化到磁盘上。
上面提到两个词active和inactive,这是从另外一个维度来分类page:
Active和Inactive是内核中用于描述页面状态的两个术语,它们指示了页面被访问的活跃程度和可能被回收的优先级。
Active(活跃)页面是指最近被访问过的页面。这些页面包含了进程当前正在使用或最近使用过的数据。内核会根据页面的活跃程度来决定其在内存中的保留优先级。由于这些页面被频繁访问,内核通常会尽量将其保留在内存中,以提高访问速度和系统性能。只有在内存紧张时,才会考虑将活跃页面置换出去。
Inactive(不活跃)页面是指较长时间没有被访问过的页面。这些页面包含了过去被使用过,但是当前并没有被活跃访问的数据。虽然这些页面不再被频繁访问,但是由于内存空间充足,暂时不需要将其回收。当系统需要更多内存来分配给其他进程或用于其他目的时,内核可能会选择从不活跃页面中回收内存。
需要注意的是,活跃和不活跃页面仅表示页面的访问情况和内核对页面的管理优先级,并不意味着页面的内容是否有效或过期。这两者都是内核在内存管理中用于优化内存使用的概念,以提高系统的性能和资源利用效率。
3. Page Cache的优缺点
3.1 Page Cache 的优势
1.加快数据访问
如果数据能够在内存中进行缓存,那么下一次访问就不需要通过磁盘 I/O 了,直接命中内存缓存即可。
由于内存访问比磁盘访问快很多,因此加快数据访问是 Page Cache 的一大优势。
2.减少 I/O 次数,提高系统磁盘 I/O 吞吐量
得益于 Page Cache 的缓存以及预读能力,而程序又往往符合局部性原理,因此通过一次 I/O 将多个 page 装入 Page Cache 能够减少磁盘 I/O 次数, 进而提高系统磁盘 I/O 吞吐量。
3.2 Page Cache 的劣势
page cache 也有其劣势,最直接的缺点是需要占用额外物理内存空间,物理内存在比较紧俏的时候可能会导致频繁的 swap 操作,最终导致系统的磁盘 I/O 负载的上升。
Page Cache 的另一个缺陷是对于应用层并没有提供很好的管理 API,几乎是透明管理。应用层即使想优化 Page Cache 的使用策略也很难进行。因此一些应用选择在用户空间实现自己的 page 管理,例如 MySQL InnoDB 存储引擎以 16KB 的页进行管理。
Page Cache 最后一个缺陷是在某些应用场景下比 Direct I/O 多一次磁盘读 I/O 以及磁盘写 I/O。