当前位置: 首页 > Linux

Linux 日志文件系统原来是这样工作的

时间:2023-04-06 01:46:32 Linux

这就是Linux日志文件系统最初的工作方式。原子操作,因为写一个文件不仅涉及到用户数据,还包括Superblock、inodebitmap、inode、datablockbitmap等元数据,所以写操作不能一步完成。如果其中任何一个步骤被打断,都会导致数据不一致或损坏。举个简单的例子,我们写一个文件,包括以下几个步骤:从数据块位图中分配一个数据块;在inode中添加指向数据块的指针;将用户数据写入数据块。如果第2步完成但第3步没有完成,结果就是数据损坏,因为文件认为数据块是自己的,但里面的数据实际上是垃圾;如果步骤2完成了,1没有完成,结果是元数据不一致,因为文件已经把数据块占为己有,但是文件系统还是认为数据块没有分配,然后可能分配数据块到其他文件,导致数据被覆盖;如果第1步完成,第2步没有完成,结果是文件系统分配了一个数据块,但是没有文件使用这个数据块,造成空间浪费;如果步骤3完成了,但是2没有完成,结果就是用户数据写入了硬盘数据块,但是白写了,因为文件不知道这个数据块是自己的。日志文件系统(JournalFileSystem)就是为解决上述问题而诞生的。它的原理是在写操作之前,预先记录下即将到来的步骤(称为事务),并保存在文件系统上的单独空间中。这就是所谓的journal,也叫Write-aheadlogging,日志保存成功后,才进行真正的写操作,将文件系统的元数据和用户数据写入硬盘(称为checkpoint),这样在写操作过程中断电的情况下,下次挂载文件时,系统只是重新执行之前保存的日志(术语称为重放),避免了上述数据损坏的情况。有人问在保存日志的过程中突然断电了怎么办?最初的想法是一次性将一条日志的数据写入硬盘,相当于一个原子操作。但是,这是不可行的,因为硬盘通常以512字节为单位进行操作,日志数据不可能超过512字节。写过一次。所以其实我们就是这样做的:为每条日志设置一个终结符,只有在日志写入成功后才写入终结符。如果一条日志没有对应的终止符,那么它会被视为无效日志,直接丢弃,这样可以保证日志中的数据是完整的。日志对应的写操作完成后就没有用了,可以释放占用的硬盘空间。保存日志的硬盘空间是有限的,而且是循环使用的,所以日志又叫循环日志。至此,我们可以总结出日志文件系统的工作步骤:日志写入:将事务写入日志;Journalcommit:在一条日志被保存后写入终结符;Checkpoint:执行真正的写操作,并将元数据(metadata)和用户数据(userdata)写入文件系统;释放:回收日志占用的硬盘空间。上述方法还将用户数据记录在日志中,称为DataJournaling。LinuxEXT3文件系统支持这种方法。这种方法存在一个效率问题:元数据(metadata)和Userdata实际上在硬盘上写了两次,一次在journal,一次在文件系统。元数据无非就是如此,用户数据通常都比较大,复制几GB的电影文件还要乘以2,确实降低了效率。一种更有效的方法是MetadataJournaling,它不会在日志中记录用户数据。防止数据损坏的方法是先写用户数据再写日志,也就是在上面的“日志写入”中先写用户数据,这样可以保证只要日志有效,对应的用户数据就是也有效。一旦断电,最坏的结果就是最后一条日志没有记录下来,那么相应的用户数据也会丢失,效果和DataJournaling一样。重要的是保证文件系统的一致性和完整性。MetadataJournaling也称为OrderedJournaling,大多数文件系统都使用这种方法。与LinuxEXT3文件系统一样,您也可以选择DataJournaling或OrderedJournaling。参考:崩溃一致性:FSCK和日志来源:http://linuxperf.com/?p=153