前段时间在开发一个使用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

给回调函数的参数

structlist 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 磁盘缓存设置,Linux下的磁盘缓存相关推荐

  1. linux 用户配额设置,Linux系统edquota命令:修改用户(群组)的磁盘配额

    针对用户和群组的配额限制(Quota),不仅可以手动控制开启和关闭,还可以手动修改配额参数,即使用 edquota 命令. edquota 命令,是 edit quota 缩写,用于修改用户和群组的配 ...

  2. 【转载】uTorrent缓存设置,防止出现磁盘负荷100%

    http://blog.sina.com.cn/s/blog_563fbc8c01011vod.html 昨晚半夜需要在家里Down一个PT,很久没在家里Down了,在小本(D430,天杀的1.8寸硬 ...

  3. uTorrent缓存设置,防止出现磁盘负荷100%

    昨晚半夜需要在家里Down一个PT,很久没在家里Down了,在小本(D430,天杀的1.8寸硬盘)上安装了utorrent,800KB/s的速度很爽,结果下载不到几分钟,就因为磁盘负荷100%,软件自 ...

  4. linux+ip+路由设置,Linux下IP巧设置-网管专栏,防火墙和路由

    如何实现ip伪装?假设你现在有一台linux主机通过ddn专线连接到internet上,有自己的ip和域名,同时还与20台win95工作站通过hub连接,你现在完全可以通过ip伪装来实现这20台win ...

  5. linux系统引导设置,Linux操作系统GRUB引导程序配置方法大全 - 技术文档 - 新手入门 Linux时代......

    1. GRUB 介绍 计算机在启动的时候,首先由BIOS中的程序执行自检,自检通过后,就根据CMOS 的配置找到第一个可启动磁盘的MBR中的Boot Loader程序(一般在启动盘的第一个物理扇区,占 ...

  6. linux 临时文件夹设置,Linux 系统 tmp 目录的安全设置

    在Linux系统中,至少有两个目录保存着系统的临时文件,一个就是 /tmp,另外一个是 /var/tmp.这两个目录有一个共同点就是所有用户在该目录下拥有可读写,可执行的权限,参考截图: 因为两个目录 ...

  7. linux 系统swap设置,Linux 系统swap 设置

    1.打开终端,切换到root用户,输入:free -m查看内存状态 [root@lxt lxt]# free -m total used free shared buffers cached Mem: ...

  8. 防火墙策略添加linux,通过iptables设置Linux防火墙INPUT策略

    原标题:通过iptables设置Linux防火墙INPUT策略 小白电脑课堂开课啦!游戏团战就死机,多半是废了.大家好我是小白.说到防火墙,同学们都会想到开了防火墙就会卡的Windows.而在Linu ...

  9. linux共享文件权限设置,linux – Windows更改Samba文件共享中的文件权限

    我安装了一个外部USB驱动器,用于CentOS上的文件共享.所有客户端访问共享都是Windows XP或7.在Windows中,我使用"用户帐户"中的"管理您的凭据&qu ...

最新文章

  1. Flutter专题1-环境搭建
  2. htpc电脑方案_我终于定稿了客厅HTPC的方案: Matx机箱小喆B3卧倒
  3. java 多线程并发 问题_JAVA多线程和并发基础面试问答
  4. react 判断图片是否加载完成_如何判断图片(img)是否已经加载成功--基于react...
  5. 用Docker构建LNMP环境(上)
  6. FFmpeg 是如何实现多态的?
  7. 计算机英语短文互译,中英文互译的英语短文
  8. JAVA设置输入数据范围,如何使用Apache POI(SXSSF)为特定单元格设置数据(数字)格式区域设置?...
  9. tomcat ---- 常用服务器
  10. 30天扣篮训练计划_明日之后:网易CH用心良苦?狼人画出“辐射高校30天计划”,绝了...
  11. 小文件复制为什么那么慢_为什么最近手机网速那么慢?原因是……
  12. api调用实例python_调用阿里云API 的demo示例(java/python)
  13. basys3利用microblaze连接Pmod OLEDrgb
  14. CTF-Mayday
  15. vs2015未能正确加载“ProviderPackage”包
  16. JavaScript —— Symbol数据类型之不延伸
  17. IEC104规约学习笔记
  18. 百度地图-手动JS触发自定义Marker覆盖物点击事件
  19. dw读取access中的图片_DreamWeaver入门必看:ACCESS数据库(三)
  20. 使用python调用百度API实现文字转语音功能

热门文章

  1. chrome不支持form.submit的解决方案_javascript技巧
  2. 如何在matlab中建立水箱模型_在MATLAB中实现水箱液位控制系统的设计
  3. 山东大学 2020级计算机系统原理——拆解二进制炸弹
  4. 在 UltraEdit 和 UEStudio 中开始使用 Perl 正则表达式
  5. Python爬虫实战,pymongo模块,Python实现数据分析国外人为啥喜欢李子柒
  6. 你有遇到客户给你发假水单的事吗?最后都怎么识别出来了?
  7. 编码孔径成像-编解码孔径的设计(MURA均匀冗余阵列)
  8. 洛谷 P-4045 密码(AC自动机+状态压缩+数位DP+乱搞)
  9. hdu 2023 求平均成绩
  10. 【263期】面试官问:假设有一千万数据,怎么快速查询?