【操作系统】【读书笔记】崩溃一致性问题

崩溃一致性:FSCK和日志

崩溃是什么

  • 持久性:文件系统的数据存储在硬盘上,因此必须长期存在

  • 不一致:如果某个操作的完成有多个步骤,其中某一步做完后系统崩溃,则会发生不一致的情况

    • 参考数据库的事务处理
  • 例子:向VSFS的一个文件追加数据,那么文件系统需要进行多次写操作:

    • 需要修改文件的inode
    • 需要写文件的data块
    • 如果空间不足需要分配新数据块,那么需要写dbitmap区域

    其中的任两步操作之间都可能会系统崩溃,例如:

    • 只写入了数据块
      • 这种情况对于文件系统一致性毫无影响,仿佛写入没有发生过一样。只不过用户体验不好
    • 只写入了inode更新
      • 这种情况下,由于数据块没有写入,因此如果根据inode读数据区会读到垃圾
    • 只写入了bitmap更新
      • 这种情况下,问题很大,空间实际上没有被使用,但是显示已分配,故会导致空间泄露(并且如果不做处理,则会永远永远泄露,因为磁盘是长久存储)
    • 等等
  • 理想:文件系统从一个一致性状态,原子地移动到另一个状态

fsck的解决方法

  • fsck:file system checker,一种早期系统用来处理崩溃一致性问题的方法
    • 目标:确保文件系统元数据一致性
    • 思路:不处理不一致的发生,而是在发生后修复他们(重启的时候)
  • fsck原理:在系统启动时运行fsck程序,处理不一致的情况
    • 超级块检查:检查超级块是否合理
    • 空闲块检查:扫描inode、间接块、双重间接块等等,以这些信息去更新bitmap(也就是说,比起bitmap,系统更信任inode的内容)
    • inode状态:如果存在问题并且不易修复,则fsck直接清除该inode,并且更新相应的inode位图
    • inode链接:检索引用计数,如果计算的计数与inode中的计数不一样,则更新inode中的计数;如果没有目录引用inode,则将该文件移动到lost + found目录
    • 检查重复:如果两个inode引用同一个数据块,则会清除明显不对的inode,或者复制一份
    • 坏块检查:扫描指针,如果指针显然不正确,则会删除该指针
    • 目录检查:检查每个目录是否有.和…,引用的每个inode是否已经分配等等
  • fsck的问题
    • 太慢。每次启动系统都需要全面扫描一遍磁盘
    • 很没必要。文件系统崩溃只是极少发生的情况,而且出问题的一般都是少数文件,因此每次都扫描所有文件的代价太大了

日志的解决办法

  • 思想:借鉴数据库的日志思想,每次写磁盘之前,都先写日志

    • 实现思路:为磁盘加上一个journal段,专用于存放日志 在这里插入图片描述
  • 数据日志:

    • 日志类型

      • 物理日志:日志内容即写入的数据内容。本笔记中说的都是物理日志
      • 逻辑日志:日志内容指引数据如何修改。可以节省空间,但是更复杂
    • 操作

      1. 每次写磁盘数据之前,都先写TxB(起始标识)、待写数据、TxE(结束标识)进磁盘日志区
      2. 写完TxE后,将数据写入磁盘数据块(这个步骤称为加检查点)
    • 流程:日志写入、日志提交(写入TxE)、加检查点(实际写入磁盘)
      在这里插入图片描述

    • 一些小问题

      • 如果一次写入TxB、待写数据、TxE,可能会出现问题:磁盘会对写入进行优化,使得写入不一定按顺序进行,可能导致TxE先于待写数据写入磁盘
        • 解决方法:不能一次写入,先写TxB和待写数据,最后再写TxE
      • 写缓冲的存在使得顺序可能发生问题
        • 解决方法:禁用写缓冲
      • 写入日志的效率低
        • 原因:先写TxB和待写数据,最后再写TxE,可能造成额外的磁盘旋转
        • 解决:TxB和TxE中都存一个日志内容的校验和。在执行恢复操作时,如果校验不匹配,则不执行该事务(因为该事务出错了)
  • 恢复操作

    • 操作:崩溃后,根据日志恢复:

      • 如果日志不完整(没有TxE),则跳过该日志
      • 如果日志完整,则重做日志
        • 即使该事务已经执行完毕,重做也不影响,仅仅是进行了冗余操作。由于崩溃不常发生,故可以接受
    • 优化1:使用全局事务缓存

    • 优化2:使日志有限

      • 问题:过长的日志会使得崩溃后的恢复操作消耗很大时间

      • 解决思路:加检查点后的事务,已经真实地写入了磁盘,可以安全的从journal中删除

      • 解决方法:将日志视为循环数据结构,一旦事务被加检查点,则释放其空间并且允许重用

        • 引入日志超级块,标记日志事务是否已经加检查点(空间是否可以重用)
          在这里插入图片描述
    • 问题:效率太低,每个数据块都需要写入磁盘两次(日志一次,数据块一次)

      • 由于崩溃是少见情况,故这样的代价不值得
  • 元数据日志

    • 思路:对数据日志进行了改良,只存元数据,不存数据

    • 问题1:虽然可以保证一致性,但是可能出现元数据更新成功而数据更新不成功的情况,可能会导致指针指向垃圾数据的情况

      • 解决思路:先写入数据,然后再写入日志元数据
    • 步骤

      1. 数据写入磁盘
      2. 日志元数据写入
      3. 日志提交
      4. 加检查点元数据
      5. 释放(已经加检查点的日志)

      注意:其中1和2顺序不限定,但是3必须在1、2都完成后再做

    • 问题2:删除文件情况下的块复用问题

      • 描述:因为目录被视为元数据,故目录更新也要写入日志中。此时如果删除了该目录导致对应的位置空出,然后又新建并写入(原目录所在位置)一个文件,由于文件的数据操作不写日志,如果此时发生崩溃,那么恢复后文件的内容会被之前的目录内容覆盖(因为目录内容是写入日志里的)
      • 解决:可以永远不重复使用块,直到块的删除加上检查点;Linux ext3中的做法是添加撤销操作到记录中
  • 总结:数据日志和元数据日志的时间线
    在这里插入图片描述

其他解决思路

  • 软更新:对文件系统所有写入操作进行排序,确保永远不会产生不一致的情况
  • 写时复制(COW)
  • 基于反向指针的一致性
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值