转自:http://blog.csdn.net/cywosp/article/details/21126161

前段时间在开发一个使用SSD做缓存的系统,在高速写入数据时会出现大量的磁盘缓存。太多的磁盘缓存如果没有及时的写入磁盘中,在机器出现问题时是非常危险的,这样会导致很多的数据丢失,但是如果实时的将数据刷入磁盘中,这样写入效率有太低了。为了弄明白Linux系统的这种磁盘写入特性,最近深入的学习了一下。
    VFS(Virtual File System)的存在使得Linux可以兼容不同的文件系统,例如ext3、ext4、xfs、ntfs等等,其不仅具有为所有的文件系统实现一个通用的外接口的作用,还具有另一个与系统性能相关的重要作用——缓存。VFS中引入了高速磁盘缓存的机制,这属于一种软件机制,允许内核将原本存在磁盘上的某些信息保存在RAM中,以便对这些数据的进一步访问能快速进行,而不必慢速访问磁盘本身。高速磁盘缓存可大致分为以下三种:
  • 目录项高速缓存——主要存放的是描述文件系统路径名的目录项对象
  • 索引节点高速缓存——主要存放的是描述磁盘索引节点的索引节点对象
  • 页高速缓存——主要存放的是完整的数据页对象,每个页所包含的数据一定属于某个文件,同时,所有的文件读写操作都依赖于页高速缓存。其是Linux内核所使用的主要磁盘高速缓存。
正是由于缓存的引入,所以VFS文件系统采用了文件数据延迟写的技术,因此,如果在调用系统接口写入数据时没有使用同步写模式,那么大多数据将会先保存在缓存中,待等到满足某些条件时才将数据刷入磁盘里。
 
内核是如何将数据刷入磁盘的呢?在看完以下两点后就能得到答案。
 
1. 把脏页写入磁盘
    正如我们所了解的,内核不断用包含块设备数据的页填充页高速缓存。只要进程修改了数据,相应的页就被标记为脏页,即把它的PG_dirty标志位置。
    Unix系统允许把脏缓冲区写入块设备的操作延迟执行,因为这种策略可以显著地提高系统的性能。对高速缓存中的页的几次写操作可能只需对相应的磁盘块进行一次缓慢的物理更新就可以满足。此外,写操作没有读操作那么紧迫,因为进程通常是不会因为延迟写而挂起,而大部分情况都因为延迟读而挂起。正是由于延迟写,使得任一物理块设备平均为读请求提供服务将多于写请求。
一个脏页可能直到最后一刻(即直到系统关闭时)都一直逗留在主存中。然而,从延迟写策略的局限性来看,它有两个主要的缺点:
  一、如果发生了硬件错误或者电源掉电的情况,那么就无法再获得RAM的内容,因此,从系统启动以来对文件进行的很多修改就丢失了。
  二、页高速缓存的大小(由此存放它所需的RAM的大小)就可要很大——至少要与所访问块设备的大小不同。
因此,在下列条件下把脏页刷新(写入)到磁盘:
  • 页高速缓存变得太满,但还需要更多的页,或者脏页的数量已经太多。
  • 自从页变成脏页以来已过去太长时间。
  • 进程请求对块设备或者特定文件任何待定的变化都进行刷新。通过调用sync()、fsync()或者fdatasync()系统调用来实现。
缓冲区页的引入是问题更加复杂。与每个缓冲区页相关的缓冲区首部使内核能够了解每个独立块缓冲区的状态。如果至少有一个缓冲区首部的PG_Dirty标志被置位,就应该设置相应缓冲区页的PG_dirty标志。当内核选择要刷新的缓冲区时,它扫描相应的缓冲区首部,并只把脏块的内容有效的写到磁盘。一旦内核把缓冲区的所有脏页刷新到磁盘,就把页的PG_dirty标志清0。
 
2. pdflush内核线程
    早期版本的Linux使用bdfllush内核线程系统地扫描页高速缓存以搜索要刷新的脏页,并且使用另一个内核线程kupdate来保证所有的页不会“脏”太长时间。Linux 2.6用一组通用内核线程pdflush替代上述两个线程。
这些内核线程结构灵活,它们作用于两个参数:一个指向线程要执行的函数的指针和一个函数要用的参数。系统中pdflush内核线程的数量是要动态调整的:pdflush线程太少时就创建,太多时就杀死。因为这些内核线程所执行的函数可以阻塞,所以创建多个而不是一个pdflush内核线程可以改善系统性能。
根据下面的原则控制pdflush线程的产生和消亡:
  • 必须有至少两个,最多八个pdflush内核线程
  • 如果到最近的1s期间没有空闲pdflush,就应该创建新的pdflush线程
  • 如果最近一次pdflush变为空闲的时间超过了1s,就应该删除一个pdflush线程
所有的pdflush内核线程都有pdflush_work描述符,其数据结构如下:
类型
字段
说明
struct task_struct
who
指向内核线程描述符的指针
void (*) (unsigned long)
fn
内核线程所执行的回调函数
unsigned long
arg0
给回调函数的参数
struct list head
list
pdflush_list链表的链接
unsigned long
when_i_went_to_sleep
当内核线程可用时的时间(以jiffies表示)
当系统没有要刷新的脏页时,pdflush线程会自动处于睡眠状态,最后由pdflush_operation()函数来唤醒。那么在这个过程中pdflush内核线程主要完成了哪些工作呢?其中一些工作与脏数据的刷新有关。尤其是pdflush通常执行下面的回调函数之一:
    1. background_writeout(): 系统地扫描页高速缓存以搜索要刷新的脏页。
为了得到需要刷新的脏页,就要彻底的搜索与在磁盘上有映像的索引节点相应的所有address_space对象(是一棵搜索树)。由于页高速缓存可能有大量的页,如果用一个单独的执行流来扫描整个高速缓存,会令CPU和磁盘长时间繁忙,因此,Linux使用一种复杂的机制把对页高速缓存的扫描划分为几个执行流。当内存不足或者用户显式的(用户态进程发出sync()系统调用等)调用请求刷新操作时会执行wakeup_bdflush()函数。wakeup_bdflush()函数会调用pdflush_operation()唤醒pdflush内核线程,并委托它执行回调函数background_writeout()。background_writeout()函数有效的从页高速缓存中获得指定数量的脏页,并把它写回磁盘。此外,执行background_writeout()函数的pdflush内核线程只有在满足以下两个条件下才能被唤醒:一是对页高速缓存中的页内容进行了修改,二是引起脏页部分增加到超过某个脏背景阈值。背景阈值通常设置为系统中所有页的10%,不过可以通过修改文件/proc/sys/vm/dirty_background_ratio来调整该值。
    2. wb_kupdate():检查页高速缓存中是否有“脏”了很久时间的页,避免当一些页很久没有被刷新时发生饥饿危险。
 内核在初始化期间会建立wb_timer动态定时器,其的定时间距为dirty_writeback_centisecs文件中所规定的几百分之一秒(通常是500分之一秒,不过可以通过修改/proc/sys/vm/dirty_writeback_centisecs文件调整该值)。定时器函数会调用pdflush_operation()函数,然后将wb_kupdate()函数的地址传入。wb_kupdate()函数遍历页高速缓存搜索陈旧的脏索引节点,把已保持脏状态时间超过30秒的页都写到磁盘,之后重置定时器。

Linux下的磁盘缓存的更多相关文章

  1. linux下测试磁盘的读写IO速度-简易方法

    linux下测试磁盘的读写IO速度-简易方法 参考资料:https://blog.csdn.net/zqtsx/article/details/25487185 一:使用hdparm命令 这是一个是用 ...

  2. Linux下的磁盘分割和文件系统

    一.各硬件装置在Linux下的文件名 1.IDE硬盘机 在Linux内的文件名: /dev/hd[a-d]  (a-d 刚好是四个这个是有原因的具体如下) 解释:以 IDE 接口来说,由于一个 IDE ...

  3. Linux下查看磁盘挂载的几种方法

    Linux下查看磁盘挂载的几种方法 第一种方法:df命令 # df -hT Filesystem Type Size Used Avail Use% Mounted on devtmpfs devtm ...

  4. Linux下查看磁盘挂载的三种方法

    Linux下查看磁盘挂载的三种方法 2009-06-05 23:17 好久没有更新日志了,呵呵.不是没有要写的东东.实在抽不出时间来写,要准备公司的考试呢,C++考试.已经有七个月没有写C++代码了, ...

  5. Linux 下测试磁盘读写 I/O 速度的方法汇总

    在分布式异构存储系统中,我们经常会需要测量获取不同节点中硬盘/磁盘的读写 I/O 速度,下面是 Linux 系统下一些常用测试方法(之后不定期更新): 1.使用 hdparm 命令这是一个是用来获取A ...

  6. Linux下查看磁盘与目录的容量——df、du

    df:列出文件系统的整体磁盘使用量: du:评估文件系统的磁盘使用量(常用于评估目录所占容量) df参数: -a:列出所有的文件系统,包括系统特有的/proc等文件系统 -k:以KB的容量显示各文件系 ...

  7. Linux下刷新DNS缓存(Ubuntu/CentOS)

    现在很多Linux发行版都没有内置DNS本地缓存,Linux不像Windows那样可以使用ipconfig /flushdns来刷新,在Linux下无需刷新,因为本身没有缓存: 当然,如果非要缓存刷新 ...

  8. LINUX下添加磁盘空间的方法详解

    给Linux系统添加磁盘空间在工作会经常遇到. 在添加第二块磁盘一般系统默认为hdb(IDE硬盘)sdb(SCSI 硬盘),以hdb为例. linux-isep:~ # fdisk /dev/hdb ...

  9. Linux下查看磁盘剩余空间和文件夹大小

    1. du -sh 查看当前文件夹大小 2. du -sh * | sort -n 列出当前文件夹下的所有文件夹及其大小,并按照文件夹大小排序 du - sh *  //查看当前文件夹下所有文件的大小 ...

随机推荐

  1. win2012R2无法打开匿名级安全令牌

    解决办法:  1.输入“dcomcnfg.exe”,打开组件服务管理. 2.展开组件服务,计算机,右击我的电脑,选择属性. 3.在默认属性选项卡中,      选择:- 勾选“在此计算机中启用分布式C ...

  2. 点击出现黑色背景的解决:-webkit-tap-highlight-color:rgba(0,0,0,0)

    在手机上(iphone)点击按钮的时候,屏幕总会闪动一下,这让页面看起来很不友好也不流畅.解决方案加了一句css就解决了: -webkit-tap-highlight-color:rgba(0,0,0 ...

  3. Android组件间通信库EventBus学习

    项目地址:   https://github.com/greenrobot/EventBus EventBus主要特点 1. 事件订阅函数不是基于注解(Annotation)的,而是基于命名约定的,在 ...

  4. 【ORACLE】ORA-27102: out of memory报错的处理

    ************************************************************************ ****原文:blog.csdn.net/clark_ ...

  5. 转:RC复位电路的原理及其复位时间的计算

    RC复位电路的原理及其复位时间的计算   低电平有效复位电路如下 此复位电路是针对低电平有效复位而言的,其中二极管是起着在断电的情况下能够很快的将电容两端的电压释放掉,为下次上电复位准备. 假设电容两 ...

  6. Nginx负载均衡简易配置

    多台Web服务器水平扩展,进行负载均衡对外服务,是一种很常见的方案. 常用方法用DNS轮询,LVS. DNS轮询虽然有配置简单的有点,但无法实现健康检查,DNS修改需要较长时间失效,对于无域名的内部服 ...

  7. 小程序框架MpVue踩坑日记(一)

    小程序也做了几个小功能模块了,总觉得需要总结一下,踩坑什么的还是得记录一下啊. 好吧,其实是为了方便回顾 首先,说到小程序框架,大家都知道wepy,不过,我是没用过 美团开发团队到mpvue到是个实在 ...

  8. tableView的cell显示不全的问题

    如果是最上面的cell没有显示完整 1.重新设置tableview的frame: 例如你的搜索框高度为50,那么设置self.tableview.frame= CGRectMake(0,50,self ...

  9. TP框架---thinkphp模型

    1.获取系统常量信息的方法:在控制器DengLuController里面下写入下面的方法,然后调用该方法. public function test() { //echo "这是测试的&qu ...

  10. Grunt是什么,以及它的一些使用方法

    ♥什么是Grunt Grunt和 Grunt 插件是通过 npm 安装并管理的,npm是 Node.js 的包管理器.grunt是基于node 更多插件请访问:http://www.gruntjs.n ...