您的位置:首页 > 其它

向下之旅(二十二):页高速缓存和页回写

2016-03-31 14:21 267 查看
  页高速缓存是Linux内核实现的一种主要磁盘缓存。它主要用来减少对磁盘的I/O操作。即通过把磁盘中的数据缓存到物理内存汇总,把对磁盘的访问变成对物理内存的访问。

  磁盘高速缓存的价值在于两个方面:第一,访问磁盘的速度要远远低于访问内存的速度,因此,从内存访问数据比从磁盘访问速度更快。第二,数据一旦被访问,就很有可能在短期内再次被访问到。这种在短时期内集中访问同一片数据的原理被称为临时局部原理。该原理能保证:如果在第一次访问的时候在物理内存中缓存它,那就极有可能在短期内再次被高速缓存命中(即访问到高速缓存中的数据)。

  页高速缓存是由RAM中的物理页组成的,缓存中的每一页都对应着磁盘块的多个块。

  也可通过块I/O缓冲区把独立的磁盘块与页高速缓存联系在一起。

  举个例子,当使用文件编辑器打开一个源程序文件时,该文件的数据就被调入内存。编辑该文件的过程中,越来越多的数据会被相继的调入内存页。最后,当你编译它的时候,本应从磁盘中读取,但是此时内核可以直接使用页高速缓存中的页。因为用户往往会反复读取或操作同一个文件,所以页高速缓存能减少大量的磁盘操作。

  页高速缓存

  页高速缓存缓存的是页面,缓存中的页来自正规文件、块设备文件和内存映射文件的读写,所以页高速缓存内就包含了最近被访问过的文件的全部页面。在执行I/O操作前,内核会检查数据是否已经在页高速缓存中了,以此减少对磁盘的访问。

  address_space对象

  一个物理页可能由多个不连续的物理磁盘块组成(比如在x86系统上,一个物理页的大小是4KB,而一个块的大小一般是512字节,一般要8个左右才能填满一个块),所以页高速缓存中检测数据是否被缓存是件非常困难的事,不可用设配名和块号来做页高速缓存中数据的索引。

  因此,Linux页高速缓存使用address_space结构体描述页高速缓存中的页面。结构如下:

  


  address_space结构通常会和某些内核对象关联。通常,会与一个索引节点(inode)关联,这时host域就会指向该索引节点。若关联对象不是一个索引节点的话,如swapper,host域就会被置为NULL。

  a_ops域指向地址空间对象中的操作函数表,这与VFS对象及其操作表关系类似。操作函数表用address_space_operations结构体表示,其结构如下:

  


  这里面readpage()和writepage()两个方法最为重要,读操作是,如果搜索的页没有在高速缓存中,那么内核将分配一个新的页面,然后将其加入到页高速缓存中。最后,需要的数据从磁盘中读入,再被加入页高速缓存,然后返回给用户。写操作和读操作有少许不同,首先,在页高速缓存中搜索需要的页,如果不要的页不在高速缓存中,那么内核在高速缓存中新分配一空闲项,下一步,prepare_write()方法被调用,创建一个写请求,接着数据从用户空间拷贝到了内核缓冲,最后通过commit_write()函数将数据写入磁盘。

  基树

  页高速缓存通过两个参数——address_space对象和一个偏移量进行搜索,检索页高速缓存。因为每次页I/O操作都要进行搜索检查,所以必须要保证搜索的效率。每个address_space对象都有唯一的基树(radix tree),它保存在page_tree结构体中,基树是一个二叉树,只要指定了文件的偏移量,就可以在基树中迅速检索到希望的数据。2.6内核以前采用全局页散列表。

  缓冲区高速缓存

  在2.2版本的内核中,存在两个独立的磁盘缓存:页高速缓存和缓冲区高速缓存。前者缓存页,后者缓存缓冲,从2.4版本开始,统一了这两种缓存,现在Linux只有唯一的磁盘缓存——页高速缓存。

  即使如此,内核仍然需要在内存中使用缓冲来表示磁盘块,幸好,缓冲是用页映射块的,所以它正好在页高速缓存中。

  pdflush后台例程

  由于页高速缓存的缓存作用,写操作实际上会被延迟。当页高速缓存中的数据比后台存储的数据更新时,则该数据被称为脏数据。在内存中累计起来的脏页最终必须被写回磁盘。在以下两种情况发生时,脏页被写回磁盘:

  1.当空闲内存低于一个特定的阈值时,内核必须将脏页写回磁盘,以便释放内存。

  2.当脏页在内存中驻留时间超过一个特定的阈值时,内核必须将超时的脏页写回磁盘,以确保脏页不会无限期的驻留在内存中。

  上面两种工作的目的完全不同,在2.6内核中,由一组内核线程—pdflush后台回写例程—统一执行两种工作。前者的目的在于可用物理内存过低时,释放脏页以重新获得内存。它会一直写出数据,直到满足:

  1.已经有指定的最小数目的页被写到磁盘

  2.空闲内存数已经回升,超过了阈值。

  以此来确保减轻系统内存不足的压力。

  后者目的,pdflush后台例程会被周期性唤醒(和空闲内存是否过低无关),将那些在内存中驻留时间过长的脏页写出,确保内存中不会有长期存在的脏页。防止系统发生崩溃等造成脏数据的丢失。

  下表列出了与pdflush相关的所有可变设置变量:



  膝上型电脑模式

  膝上型电脑模式是一种特殊的页回写策略,该策略主要意图是将硬件转动的机械行为最小化,允许硬盘尽肯能长时间的停滞,以此延长电池供电时间。

  膝上型电脑模式的页回写行为与传统方式相比只有一处变化,除了当缓存中的页面太久时要执行回写脏页以外,pdflush还会找准磁盘运转的时机,把所有其他的物理磁盘I/O、刷新脏缓冲等统统写回磁盘,以便保证不会专门的为了写磁盘而去主动激活磁盘运行。

  bdflush和kupdated

  在2.6版本前,pdflush线程的工作分别由bdflush和kuodated两个线程共同完成的,前者完成当系统中空闲内存消耗到特定阈值一下时,进行页回写。后者是周期的执行页回写操作。

  bdflush和pdflush的区别是只有一个bdflush后台线程,当脏数据多时,会造成阻塞。而2.6版本后,通过一个简单的算法,使得pdflush的数量可以根据页回写的时间来动态变化,提高页回写性能。

  参考自:《Linux Kernel Development》.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: