文件系统要解决的一个关键问题是怎样防止掉电或系统崩溃形成数据损坏,在此类意外事件中,致使文件系统损坏的根本缘由在于写文件不是原子操做,由于写文件涉及的不单单是用户数据,还涉及元数据(metadata)包括 Superblock、inode bitmap、inode、data block bitmap等,因此写操做没法一步完成,若是其中任何一个步骤被打断,就会形成数据的不一致或损坏。node
举一个简化的例子,咱们对一个文件进行写操做,要涉及如下步骤:linux
日志文件系统(Journal File System)就是为解决上述问题而诞生的。app
它的原理是在进行写操做以前,把即将进行的各个步骤(称为transaction)事先记录下来,保存在文件系统上单独开辟的一块空间上,这就是所谓的日志(journal),也被称为write-ahead logging,日志保存成功以后才进行真正的写操做、把文件系统的元数据和用户数据写进硬盘(称为checkpoint),这样万一写操做的过程当中掉电,下次挂载文件系统以前把保存好的日志从新执行一遍就好了(术语叫作replay),避免了前述的数据损坏场景。spa
有人问若是保存日志的过程当中掉电怎么办?最初始的想法是把一条日志的数据一次性写入硬盘,至关于一个原子操做,然而这并不可行,由于硬盘一般以512字节为单位进行操做,日志数据一超过512字节就不可能一次性写入了。因此其实是这么作的:给每一条日志设置一个结束符,只有在日志写入成功以后才写结束符,若是一条日志没有对应的结束符就会被视为无效日志,直接丢弃,这样就保证了日志里的数据是完整的。指针
一条日志在它对应的写操做完成以后就没用了,占用的硬盘空间就能够释放。保存日志的硬盘空间大小是有限的,被循环使用,因此日志也被称为circular log。日志
至此能够总结一下日志文件系统的工做步骤了:blog
以上方式把用户数据(user data)也记录在日志中,称为Data Journaling,Linux EXT3文件系统就支持这种方式,这种方式存在效率问题:事件
就是每个写操做涉及的元数据(metadata)和用户数据(user data)实际上都要在硬盘上写两次,一次写在日志里,一次写在文件系统上。元数据倒也罢了,用户数据一般比较大,拷贝几个GB的电影文件也要乘以2实在是下降了效率。
一个更高效的方式是Metadata Journaling,不把用户数据(user data)记录在日志中,它防止数据损坏的方法是先写入用户数据(user data)、再写日志,即在上述”Journal write”以前先写用户数据,这样就保证了只要日志是有效的,那么它对应的用户数据也是有效的,一旦发生掉电故障,最坏的结果也就是最后一条日志没记完,那么对应的用户数据也会丢,效果与Data Journaling丢弃日志同样,重要的是文件系统的一致性和完整性是有保证的。ci
Metadata Journaling又叫Ordered Journaling,大多数文件系统都采用这种方式。像Linux EXT3文件系统也是能够选择Data Journaling仍是Ordered Journaling的。rem
参考资料:Crash Consistency: FSCK and Journaling
来源:http://linuxperf.com/?p=153