Linux 文件读写机制

01. 基本概念

缓存

缓存是用来减少高速设备访问低速设备所需平均时间的组件,文件读写涉及到计算机内存和磁盘,内存操作速度远远大于磁盘,如果每次调用read、write都去直接操作磁盘,一方面速度会被限制,一方面也会降低磁盘使用寿命,因此不管是对磁盘的读操作还是写操作,操作系统都会将数据先缓存起来。

Page Cache

页缓存(Page Cache)是位于内存与文件之间的缓冲区,它实际上也是一块内存区域,所有的文件IO(包括网络文件)都是直接和页缓存交互,操作系统通过一系列的数据结构,比如inode, address_space, struct page,实现将一个文件映射到页的级别。很大一部分程度上,文件读写的优化就是对页缓存使用的优化。

Dirty Page

页缓存对应文件中的一块区域,如果页缓存和对应的文件区域内容不一致,则该页缓存叫做脏页(Dirty Page)。对页缓存进行修改或者新建页缓存,只要没有刷磁盘,都会产生脏页。

Linux 文件读写机制

[root@ufo130 ~]# cat /proc/meminfo | grep -E '^Cached|^Dirty'

Linux 文件读写机制

一些可以改变操作系统对脏页的回写行为的参数

[root@ufo130 ~]# sysctl -a 2>/dev/null | grep dirty
vm.dirty_background_ratio = 5
vm.dirty_background_bytes = 0
vm.dirty_ratio = 10
vm.dirty_bytes = 0
vm.dirty_writeback_centisecs = 500
vm.dirty_expire_centisecs = 3000
  • vm.dirty_background_ratio是内存可以填充脏页的百分比,当脏页总大小达到这个比例后,系统后台进程就会开始将脏页刷磁盘(vm.dirty_background_bytes类似,只不过是通过字节数来设置)

  • vm.dirty_ratio是绝对的脏数据限制,内存里的脏数据百分比不能超过这个值。如果脏数据超过这个数量,新的IO请求将会被阻挡,直到脏数据被写进磁盘

  • vm.dirty_writeback_centisecs指定多长时间做一次脏数据写回操作,单位为百分之一秒

  • vm.dirty_expire_centisecs指定脏数据能存活的时间,单位为百分之一秒,比如这里设置为30秒,在操作系统进行写回操作时,如果脏数据在内存中超过30秒时,就会被写回磁盘

  • 这些参数可以通过 sudo sysctl -w vm.dirty_background_ratio=5 这样的命令来修改,需要root权限,也可以在root用户下执行 echo 5 > /proc/sys/vm/dirty_background_ratio 来修改

02. 文件读写流程

在有了页缓存和脏页的概念后,我们再来看文件的读写流程

读文件

  • 用户发起read操作
  • 操作系统查找页缓存
  • 若未命中,则产生缺页异常,然后创建页缓存,并从磁盘读取相应页填充页缓存
  • 若命中,则直接从页缓存返回要读取的内容
  • 用户read调用完成

写文件

  • 用户发起write操作
  • 操作系统查找页缓存
  • 若未命中,则产生缺页异常,然后创建页缓存,将用户传入的内容写入页缓存
  • 若命中,则直接将用户传入的内容写入页缓存
  • 用户write调用完成
  • 页被修改后成为脏页,操作系统有两种机制将脏页写回磁盘
  • 用户手动调用fsync()
  • 由pdflush进程定时将脏页写回磁盘

页缓存和磁盘文件是有对应关系的,这种关系由操作系统维护,对页缓存的读写操作是在内核态完成,对用户来说是透明的

03. 文件读写的优化思路

不同的优化方案适应于不同的使用场景,比如文件大小,读写频次等,这里我们不考虑修改系统参数的方案,修改系统参数总是有得有失,需要选择一个平衡点,这和业务相关度太高,比如是否要求数据的强一致性,是否容忍数据丢失等等。优化的思路有以下两个考虑点。

  • 最大化利用页缓存

  • 减少系统api调用次数

第一点很容易理解,尽量让每次IO操作都命中页缓存,这比操作磁盘会快很多,第二点提到的系统api主要是read和write,由于系统调用会从用户态进入内核态,并且有些还伴随着内存数据的拷贝,因此在有些场景下减少系统调用也会提高性能。

上一篇:Linux之内存管理


下一篇:【JS】attribute 和 property 的绑定