Journaling and Log-structured file systems(日志式和日志结构文件系统)
from:https://pdfs.semanticscholar.org/presentation/45a4/c9b72ff6a2480545e3cf53b303dea9adecd7.pdf
文件系统
文件系统是数据用户层视角的永久存储容器。
- 文件是永久存储的,进程结束后依然存在。
- 文件可以被多个进程访问,是一种共享的资源。
- 文件通过路径名来定位
让我们来写一个文件
假设我们要写一个叫bar.txt的文件,这个过程需要分配许多新的数据块。
我们需要:
- 更新block bitmap —— 分配一个或多个数据block
- 更新bar.txt 文件的inode —— inode 持有文件数据块起始位置,文件的大小,访问时间等信息。
- 更新数据block —— 写入新数据
如果发生了crash怎么办?
如果存储设备崩溃了怎么办?
如果操作系统崩溃了怎么办?
从crash中幸存下来##
方法:
- 文件系统检查 —— 尽可能多的恢复
- 日志(journal) —— 把将要做的事情记录下来
- 写时复制 (copy on write) —— 创建一个副本,然后修改指针
crash 恢复
图 1
S: super block i:inode bitmap d: block bitmap
fsck /dev/sdb1
图 2
lost+found
图 3 第一列为文件的inode number
日志(journal)
我们需要将数据从一种一致的状态移动到另一种一致的状态。我们将将要做的事情记录为日志。可以成为日志或者写操作前记录。如果发生了crash,我们可以通过检查日志来重复上一序列的操作。
Linux ext2 - 无日志型
图 4
Linux ext3 - 日志型
图 5
安全的方式
提交(commit): 写入事务(transaction)
- TxB: 事务开始,标记了事务ID
- Iv2: 等待更新的inode
- Bv2:等待更新的bitmap
- Dv2:等待更新的数据block
- TxE:事务结束
检查点(checkpoint): 执行更改
- 更新block: bit maps, inode, datablock
- 删除事务
可能出现的灾难场景
事务被写入了一半。
写入了完整事务,但还没有来得及更新block。
写入了完整事务,更新了block,最后没有来得及删除事务。
等待的事务
图 6
cache层次
图 7
- fflush(): 将c库中缓存的数据刷到内核,是否缓存数据可以在编译仓库时选择。
- sync(): 将改动同步到文件系统,执行journal/checkpoint 一系列动作。
- checkpointing:将journal同步到inode, bitmaps,datablock
日志(journal)是很慢的
提交(commit):将元数据和数据以事务的方式写入
checkpointing:用事务中的数据更新文件系统的inode,bitmaps和datablock
每一个单元数据被写了两次
数据block写一次
比较快的方式:
- 提交数据:将文件数据直接写入到文件系统block
- 提交元数据:当文件数据写入到block后,将元数据(meta-data)以事务的方式提交
- checkpointing:将事务中的数据更新文件系统中的inode,bitmaps
更快的方式:
- 提交数据:将文件数据直接写入到文件系统block
- 提交元数据:将元数据(meta-data)以事务的方式提交,并不保证数据已经写入block中
- checkpointing:将事务中的数据更新文件系统中的inode,bitmaps
ext4/jdb2
- 日志(journal): 数据和元数据都通过日志写入
- 顺序式(ordered-default):数据直接写入block,元数据通过日志写入
- 回写式(write-back):在写入元数据时,不保证数据已经被全部写入block中
inode是最关键的数据
图 8
Log-structured(日志结构)文件系统
读操作主要从RAM中的文件cache中读。关键的问题都在写操作上,这种文件系统主要减少寻道操作。进行写操作时,文件系统以大块的连续segments的方式写入。文件系统的状态就是很多事件的log。
log
图 9 i:inode D: data block
inode map
图 10
inode map 持有inode number到block地址的映射