Linux : page cache 和 page wirteback

 

简单地说, 第一次读取一个文件,肯定要有一次磁盘操作。 在后来的读取,如果发现要读的内容已经在内存了,就不要进行磁盘的IO. 而写通常不会直接写到磁盘上, 而是先写到内存里面,到特定的时机再写回到磁盘。

1 LRU 和 two-list LRU
将磁盘的内容放到内存固然可以提高后来的访问性能,但因为内存是有限的,肯定会又内存不足的情况。 这时就应该将一些在将来被用到可能性小的数据赶出内存(如果这个数据已经被修改了,则要先写回磁盘,再挪位)。那么哪些数据是将来可能不被访问的呢? 早起采取的算法就是LRU(Least Recently Used), 就是按照最后访问时间进行排序,将越长时间没有访问的数据 就越有可能被敢出去。但LRU 的不足时, 有些情况,一些大的文件只被访问了一次, 例如编译了一个大的项目, 后面就不会被访问了, 太慢占用了大量的内存,但却需要较长的时间才被赶出去。 为了解决这个问题, 就引入了two-list LRU 机制。 任何文件第一次访问的时候,都会被放到一个 inactive LRU 上, 只有第二次访问的时候才会被放到acitve LRU 上。 而清除内存的时候总是先在Inactive LRU 上进行的。

2 writeback 和 flusher threads
一般情况下,写操作都是写到内存。然后有linux 进程将脏数据写回磁盘。 以下三种情况会触发writeback 操作:
2.1 当free memory 下降的一定程度, 就会触发写回操作
2.2 当脏页的数目增加到一定程度,那些够老的脏页就会被写回
2.3 应用程序要求写回。通常是为了考虑到数据安全性的问题。 可以通过sync, fsync, fdatasync 等方式来实现。

2.1 的需求是受vm.dirty_background_ratio  控制,显示的是一个百分比。 如果脏块的数量的百分比超过这个值,就会唤醒flusher 去写回脏数据。
2.2 的需求是受vm.dirty_writeback_centisecs 和 vm.dirty_expire_centisecs 控制,单位都是1/100 秒。 前者控制flusher 被唤醒的周期, 后者表示 唤醒后,多老的数据会被写回。

另外 vm.dirty_ratio  总内存的百分比, 但是是只一个进程的脏页如果高于这个值,就会被写回。

在调整这些参数之前,先要了解程序的写是否是因为2.3 的需求。 如果是这样,修改其他参数也没什么用了。 例如在Mysql 中有一系列这种参数, 控制一次写入后是否需要fsync。 如果要提高性能,先要关闭这些fsync, 然后再考虑调节这几个vm 参数。

在调整这些参数以后,再通过sar 或者pidstat 来查看io 的状况是否如预期。

3 flusher thread 和  bdflush, kupdated , pdfush
简单的说 flusher 是2.6.32的内核才引用的。主要优点是 flusher 可以启动多个线程, 不同的线程负责不同的disk spindles.  从而产生更好的性能。 这个特性经常被称为Per-backing-device based writeback。
其他的几个以后应该看不到了。也就不谈了。 它们都对device 不敏感的。


如果想清空page cache 的脏页,可以:
echo 1 > /proc/sys/vm/drop_caches

更多的vm 参数含义可以访问:
https://www.kernel.org/doc/Documentation/sysctl/vm.txt

posted @ 2013-06-07 18:30  zhifan  阅读(724)  评论(0)    收藏  举报