liwen01 2024.06.16
先提几个问题:什么是文件系统崩溃一致性?为什么会出现文件系统崩溃一致性问题?有哪些方法可以解这个问题?它们各自又有哪些局限性?
window系统电脑异常后会蓝屏、手机死机卡顿后我们会手动给它重启,大部分设备的系统在遇到不可修复的严重异常后都会尝试通过重启来恢复,因为系统重启之后,系统整体比较"干净"。
其中有一例外,就是我们希望磁盘存储的数据无论在系统出现何种异常的情况下,都能够保存好原来的数据,系统恢复后可以再找到异常前的所有数据。
文件系统崩溃一致性(Crash Consistency)是指在文件系统发生崩溃、断电或其它不可预见的故障后,文件系统能够保证数据的一致性和完整性,并能够恢复到一个合法且可操作的状态,确保系统重新启动或恢复之后,数据不会出现损坏、丢失或不一致的情况。
以ext4 文件系统举例,当我们创建一个文件系统的时候,有下面4个步骤:
因为磁盘是以扇区为最小单位,所以上面4个步骤不可能一次全部写入到磁盘中去,在1到4步骤中间的任意一个时间点系统突然崩溃,都会导致文件系统不一致。比如在2~3步骤中间断电,就会造成inode bitmap、block bitmap中标记已经使用,但是没有实际的文件与之对应,如果不回收,那么这几个块就可能永远不会被使用。
在实际使用的时候,情况会更加地复杂,因为系统为了提升文件系统的读写检索性能,在挂载文件系统的时候,系统会将文件系统的元数据缓存到内存上。如下图《图1.1 内存与存储结构》
在有缓存的情况下,数据一般是定时写入磁盘,或者是手动保存才会写入磁盘,一次完成批量数据的写入。如果在这个过程中突然异常,丢失的数据可能会更加多。
有多少人经历过电脑突然断电,辛辛苦苦写的内容全部被丢失。系统崩了,内心也崩了。
关于ext4 文件系统的详细介绍,可以查看文章《文件系统(六):一文看懂linux ext4文件系统工作原理》
解决文件系统一致性的问题,常用的方法有:日志、写时复制、Soft Update、日志文件系统,它们各有优缺点,目前并没有哪种方案可以适用所有场景。
在ext4文件系统中,有一个独立的日志数据区,它的基本思想是:先将一组操作记录到日志区(日志提交完成),然后再去实现这些操作(应用事务完成),实现结束之后再把日志擦除(日志清理完成)。
事务开始:文件系统开始一组更新操作,并开启一个新的事务
收集日志:收集所有即将修改的数据(以及在 Journal 模式下的数据)
提交日志:更新日志头,标记该事务已经提交(commit)
应用事务:将日志中的修改应用到文件系统,将数据和元数据写入最终位置
清理日志:事务完成后,日志系统清理已提交的日志记录
文件系统有了日志功能之后,在文件系统崩溃或是突然断电后就可以通过日志保持文件系统的一致性。基本的流程是,文件系统挂载后,系统会去扫描日志区域,看是否有未完成的事务,如果有,则判断该事件是否有提交:
文件系统的日志功能,它的主要优点有两个:
文件系统引入日志之后,明显的缺点有:
ext4 文件系统用JBD2实现的日志有三种模式:Writeback、Ordered、Journal
Writeback模式:
在这种模式下,元数据变更会被记录到日志中,但数据的变更不会被记录。数据写入磁盘的顺序不受元数据更新的顺序影响。
优点:性能较高,因为减少了日志记录的数据量。
缺点:数据一致性较差,在崩溃后,文件可能会包含新元数据指向的旧数据。
Ordered模式:
这是ext4文件系统的默认日志模式。元数据变更会被记录到日志中,数据的变更虽然不记录,但数据写入磁盘的顺序必须在相应的元数据更新之前。
优点:在性能和数据一致性之间提供了平衡。崩溃后,文件不会包含新元数据指向的旧数据,因为数据写入总是在元数据更新之前完成。
缺点:性能比writeback模式略低,因为需要保证数据先于元数据写入。
Journal模式:
在这种模式下,所有数据和元数据的变更都会被记录到日志中。数据和元数据都被完整地写入日志,然后再写入主文件系统。
优点:提供最高的数据一致性保障。在崩溃恢复时,所有已提交的数据和元数据变更都可以被恢复。
缺点:性能较低,因为所有数据都需要写两次,一次写入日志,一次写入主文件系统
Copy-on-Write(COW,写时复制)在在计算机中应用非常多,比较常见的是在内存中的写时复制。文件系统中的写时复制与内存中的写时复制有些不一样。在文件系统崩溃一致性中,COW它的基本原理是,在需要修改数据时,不直接在原数据位置进行修改,而是将数据复制到新位置进行修改,只有在修改完成后,才更新指针或元数据指向新的数据位置。
COW技术的核心思想是推迟实际数据写入的时间,直到必须进行修改为止。具体步骤如下:
以Btrfs为例,COW的工作流程如下:
Btrfs和ZFS:Btrfs(B-tree文件系统)和ZFS(Zettabyte文件系统)是两种广泛使用的支持COW的文件系统。它们利用COW技术来提高数据一致性和完整性。
快照和克隆:COW允许高效地创建数据快照和克隆。例如,在Btrfs中,可以通过COW技术快速创建文件系统的快照,而无需复制实际数据。
事务性操作:通过COW,文件系统中的修改可以被视为事务性操作。只有当所有修改都成功完成后,才会更新元数据指针,这确保了在崩溃发生时,文件系统处于一致的状态。
数据一致性:由于数据修改是在新位置进行的,系统崩溃时旧数据仍然保持不变,确保数据一致性。
崩溃恢复:在崩溃恢复过程中,通过检查元数据,可以快速确定哪些数据块是有效的,哪些是未完成的修改。
高效快照:COW技术允许文件系统高效地创建和管理快照,因为快照只需复制元数据指针,而不需要复制实际数据。
性能开销
磁盘空间利用效率
数据恢复和修复复杂性
硬件依赖性
Soft Updates 是通过有序地更新元数据以确保文件系统的一致性,同时尽可能减少性能开销。与日志和Copy-on-Write(COW)技术相比,Soft Updates 提供了一种不同的路径来实现崩溃一致性。
Soft Updates 的核心思想是控制文件系统元数据更新的顺序,以确保即使在系统崩溃时,文件系统仍然保持一致性。具体方法包括以下几个步骤:
创建和删除文件:
分配和释放数据块:
更新元数据:
这里介绍的日志文件系统(Log-structured File System,LFS),与上面介绍的ext4的日志功能不是同一个东西,LFS采用了完全不同的方法来管理数据和元数据,以提高性能和崩溃一致性。
日志文件系统(LFS)的核心思想是将所有数据和元数据的更新操作记录到一个连续的日志结构中,而不是直接在原数据块上进行写操作。其基本原理如下:
写操作:
后台合并:
崩溃恢复:
在嵌入式设备中, 经常使用jffs2文件系统进行参数保存,虽然jffs2 是专门为闪存设计的文件系统,但它的设计也是LFS的原理来设计的。
上面介绍了日志、写时复制、Soft Update、日志文件系统的方法来解决文件系统的一致性问题,这里还有一个问题,我们经常使用的U盘或是SD卡,它并没有使用上面的任何一种机制,为什么我们在实际使用的时候,很少能感觉到丢数据呢?甚至还经常直接热拔插它们。这个问题我们在下一篇中解释。