当前位置:嗨网首页>书籍在线阅读

43-页回写

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

2.11.3 页回写

正如2.3.6小节介绍的那样,内核通过缓冲区来延迟写操作。当进程发起写请求,数据被拷贝到缓冲区,并将该该缓冲区标记为“脏”缓冲区,这意味着内存中的拷贝要比磁盘上的新。此时,写请求就可以返回了。如果后续对同一份数据块有新的写请求,缓冲区就会更新成新的数据。对该文件中其他部分的写请求则会开辟新的缓冲区。

最后,那些“脏”缓冲区需要写到磁盘,将磁盘文件和内存数据同步。这个过程就是所谓的“回写(writeback)”。以下两个情况会触发回写:

  • 当空闲内存小于设定的阈值时,“脏”缓冲区就会回写到磁盘上,这样被清理的缓冲区会被移除,释放内存空间。
  • 当“脏”缓冲区的时长超过设定的阈值时,该缓冲区就会回写到磁盘。通过这种方式,可以避免数据一直是“脏”数据。

回写是由一组称为flusher的内核线程来执行的。当出现以上两种场景之一时,flusher线程被唤醒,并开始将“脏”缓冲区写到磁盘,直到不满足回写的触发条件。

可能存在多个flusher线程同时执行回写。多线程是为了更好地利用并行性,避免拥塞。拥塞避免(congestion avoidance)机制确保在等待向某个块设备进行写操作时,还能够支持其他的写操作。如果其他块设备存在脏缓冲区,不同flusher线程会充分利用每一块设备。这种方式解决了之前内核的一处不足: 先前版本的flusher线程(pdflush以及bdflush)会一直等待某个块设备,而其他块设备却处于空闲状态。在现代计算机上,Linux内核可以使多个磁盘处于饱和状态。

缓冲区在内核中是通过buffer _ head数据结构来表示的。该数据结构跟踪和缓冲区相关的各种元数据,比如缓冲区是否是“脏”缓冲区。同时,它还维护了一个指向真实数据的指针。这部分数据保存在页缓存中。通过这种方式,实现了缓冲子系统(buffer subsystem)和页缓存之间的统一。

在早期的Linux内核版本中(2.4以前),缓冲子系统与页缓存是分离的,因此同时存在页缓存和缓冲缓存。这意味着数据可以同时在缓冲缓存(作为“脏”缓冲区)和页缓存(用来缓存数据)中存在。不可避免地,对这两个独立缓存进行同步需要很多工作。因此,在2.4 Linux内核中引入了统一的页缓存,这个改进很不错!

在Linux中,延迟写和缓冲子系统使得写操作性能很高,其代价是如果电源出现故障,可能会丢失数据。为了避免这种风险,关键应用可以使用同步I/O来保证(在本章先前讨论过)。