linux文件系统五 PageCache的使用

一、PageCache介绍:

  Page cache是通过将磁盘中的数据缓存到内存中,从而减少磁盘I/O操作,从而提高性能。此外,

还要确保在page cache中的数据更改时能够被同步到磁盘上,后者被称为page回写(page writeback)。

一个inode对应一个page cache对象,一个page cache对象包含多个物理page。

1、PageCache的作用:

  • 缓存 I/O 使用了操作系统内核缓冲区,在一定程度上分离了应用程序空间和实际的物理设备。
  • 缓存 I/O 可以减少读盘的次数,从而提高性能。

  linux对文件的访问除了显示使用O_DIRECT标志,所有的访问都会经过pagecache。如下可以看到

读文件的两种方式,一种带O_DIRECT标志的会直接读取磁盘中的数据,另外一种是先进行预读操作,

看PageCache中是否有对应的数据(radix基树),如果有直接将对应的数据返回,这样进行的读取的操作

速度很快,不在PageCache中则将对应的数据读取到内存中,O_DIRECT标志通常用于操作大文件和

访问次数较少的文件:

2、page cache的管理:

  在Linux内核中,文件的每个数据块最多只能对应一个page cache项,它通过两个数据结构来管理这些cache项,

一个是radix tree,另一个是双向链表。Radix tree是一种搜索树,Linux内核利用这个数据结构,快速查找脏的(dirty)

和回写的(writeback)页面,得到其文件内偏移,从而对page cache进行快速定位。

  一个文件的 page cache 结构。文件被分割为一个个以 page 大小为单元的数据块,这些数据块(页)被组织成一

个多叉树(称为 radix 树)。树中所有叶子节点为一个个页帧结构(struct page),表示了用于缓存该文件的每一个页。

在叶子层最左端的第一个页保存着该文件的前4096个字节(如果页的大小为4096字节),接下来的页保存着文件第二

个4096个字节,依次类推。树中的所有中间节点为组织节点,指示某一地址上的数据所在的页。此树的层次可以从0层

到6层,所支持的文件大小从0字节到16 T 个字节。树的根节点指针可以从和文件相关的 address_space 对象(该对象

保存在和文件关联的 inode 对象中)。

二、page cache机制写回时机writeBack:

1、写入时机:

  当内核发起一个写请求时(例如进程发起write()请求),同样是直接往cache中写入,后备存储中的内容不会

直接更新。内核会将被写入的page标记为dirty,并将其加入dirty list中。内核会周期性地将dirty list中的page写回

到磁盘上,从而使磁盘上的数据和内存中缓存的数据一致。

Page cache推迟了文件写入后备存储的时间,但是dirty page最终还是要被写回磁盘的。

内核在下面三种情况下会进行会将dirty page写回磁盘:

  • 用户进程调用sync() 和 fsync()系统调用
  • 空闲内存低于特定的阈值(threshold)
  • Dirty数据在内存中驻留的时间超过一个特定的阈值

  线程群的特点是让一个线程负责一个存储设备(比如一个磁盘驱动器),多少个存储设备就用多少个线程。这

样可以避免阻塞或者竞争的情况,提高效率。当空闲内存低于阈值时,内核就会调用wakeup_flusher_threads()来

唤醒一个或者多个flusher线程,将数据写回磁盘。为了避免dirty数据在内存中驻留过长时间(避免在系统崩溃时丢

失过多数据),内核会定期唤醒一个flusher线程,将驻留时间过长的dirty数据写回磁盘。
 

2、数据的写入:

一次写数据的典型流程(不考虑异常和其它特殊情况):

1、数据在用户态的 buffer 中,调用 write 将数据传给内核;

2、数据在 Page Cache 中,返回写入的字节数(成功返回);

3、内核将数据刷新到磁盘。

相关的控制参数有:

sysctl -a | grep dirty
vm.dirty_background_bytes = 0
vm.dirty_background_ratio = 5
vm.dirty_bytes = 0
vm.dirty_expire_centisecs = 3000
vm.dirty_ratio = 10
vm.dirty_writeback_centisecs = 500
  • dirty_writeback_centisecs 表示多久唤醒一次刷新脏页的后台线程。这里的500表示5秒唤醒一次。
  • dirty_expire_centisecs 表示脏数据多久会被刷新到磁盘上。这里的3000表示 30秒。
  • dirty_background_ratio 表示当脏页占总内存的的百分比超过这个值时,后台线程开始刷新脏页。这个值如果设置得太小,可能不能很好地利用内存加速文件操作。如果设置得太大,则会周期性地出现一个写 IO 的峰值。
  • dirty_ratio 当脏页占用的内存百分比超过此值时,内核会阻塞掉写操作,并开始刷新脏页。
  • dirty_background_bytesdirty_bytes 是和 dirty_background_ratio、dirty_ratio 表示同样意义的不同单位的表示。两者不会同时生效。

参考链接:

https://cloud.tencent.com/developer/article/1143727

作者:frank_zyp 
您的支持是对博主最大的鼓励,感谢您的认真阅读。 
本文无所谓版权,欢迎转载。

发布了59 篇原创文章 · 获赞 80 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/frank_zyp/article/details/98068871