操作系统页缓存(Page Cache)庖丁解牛
核心本质:页缓存是Linux内核在内存里开辟的一块缓冲区,用来缓存磁盘上的数据块。它的目标是化解低速磁盘和高速内存之间巨大的速度鸿沟,所有读写文件的系统调用,默认都会经过页缓存。
一、底层原理拆解
磁盘IO速度极慢,内存速度比磁盘快上万倍。操作系统不会用户每次read/write就直接读写物理磁盘。
当进程发起读文件:
- 内核先去页缓存查找目标数据对应的内存页;
- 如果命中,直接把内存里的数据拷贝给应用程序,不碰磁盘,这就是缓存命中;
- 如果没有命中(缓存未命中/缺页),内核发起磁盘IO,把磁盘对应块读到内存页缓存中,再把数据交给应用,后续再次读取同一块数据,直接走缓存。
写文件流程:
- 应用调用write,数据并不会直接写到硬盘,而是写入页缓存;
- 此时页缓存里的页面标记为脏页(dirty page),代表内存中的数据和磁盘不一致;
- 内核后台有pdflush线程,会在合适时机,把脏页异步刷入物理磁盘;
- 刷盘完成后,脏页标记清除,内存页和磁盘内容保持一致。
重点:你前面Redis AOF里的fsync,就是强制把脏页从页缓存刷到磁盘,绕过操作系统后台的自动刷盘策略。write仅仅写到页缓存就返回,fsync才真正落地到硬件磁盘。
二、页缓存的内存来源
页缓存占用的内存,属于系统空闲内存。Linux的设计哲学:空闲内存不能闲置,尽量拿来做缓存提升IO性能。
当应用程序需要申请新内存时,如果页缓存占用较多,内核会回收缓存页面,释放内存给进程使用。
所以在Linux服务器看free命令,看到cached数值很大,不是内存泄露,是系统在用内存加速磁盘读写。
三、脏页的刷盘机制
脏页不会永久留在内存,内核有一套阈值控制自动刷盘:
- 当脏页总量达到系统上限,触发主动刷盘;
- 脏页存活时间超过阈值,pdflush线程会将超时脏页刷盘;
- 系统关机、卸载磁盘时,强制刷所有脏页。
这里就解释AOF的三个appendfsync选项:
- appendfsync no:Redis只write写入页缓存,不调用fsync,交给内核pdflush后台刷盘。断电时,内存页缓存中还没刷盘的脏数据直接丢失。
- appendfsync everysec:Redis每秒调用一次fsync,强制把AOF文件对应的脏页刷到磁盘。最多丢失1秒内写请求。
- appendfsync always:每一条写命令执行完成,立刻调用fsync,强制刷脏页到磁盘,几乎不丢数据,但磁盘IO压力巨大。
四、关键区分:页缓存 vs 应用层缓存
很多人混淆,这里拆清楚边界:
- 页缓存:内核层面,操作系统自带,对应用程序透明。不管PHP、Redis、Nginx,只要读写文件,自动走页缓存,应用代码不用写任何逻辑。缓存对象是磁盘文件块。
- Redis缓存:应用层缓存,用户态程序自己维护。缓存对象是业务key-value,数据直接放在Redis进程内存,不走文件、不走页缓存。
五、业务开发里的坑点
- write系统调用成功 ≠ 数据落盘。只是写入页缓存,断电依然丢数据,这是最经典误区。想要持久化安全,必须fsync。
- 服务器内存充足时,大量文件读请求几乎全部命中页缓存,磁盘IO很低;内存不足,页缓存频繁回收,大量缺页,磁盘压力飙升,性能暴跌。
- 大文件顺序读写,页缓存效果极好;随机读写,缓存命中率会下降。
- 页缓存是按内存页(4KB默认)为单位管理,不是按文件一行或者业务数据。
六、和Redis持久化联动总结
AOF日志本质就是普通磁盘文件,Redis写AOF,就是调用write写入页缓存。appendfsync控制什么时候调用fsync把脏页强制刷入磁盘。
RDB生成rdb文件,同样经过页缓存,BGSAVE写完rdb文件后,内部也会执行fsync,保证快照文件落地磁盘。
Buffer Cache(块缓冲):早期独立,新版Linux已经合并进Page Cache。Buffer用于缓存块设备裸块,Page Cache用于缓存文件。现代Linux统一为页缓存。
mmap内存映射:mmap就是把磁盘文件映射到进程虚拟内存,读写mmap内存区域,底层操作的依旧是页缓存,脏页依旧由内核异步刷盘。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)