最近个月以来Linux已经巩固了其作为服务器操作系统的地位就像集群(cluster)对于企业级的应用很重要那样日志文件系统(journaling file system)也是同样重要的
为什么日志文件系统很重要呢?它是怎样工作的呢?有哪些日志文件系统可以用于Linux?
日志文件系统比传统的文件系统安全因为它用独立的日志文件跟蹤磁盘内容的变化就像关系型数据库(RDBMS)日志文件系统可以用事务处理的方式提交或撤消文件系统的变化
Ext不能满足要求
尽管Linux可以支持种类繁多的文件系统但是几乎所有的Linux发行版都用ext作为默认的文件系统Linux可以支持的文件系统有FATVFATHPFS(OS/)NTFS(Windows NT)Sun的UFS等等
ext的设计者主要考虑的是文件系统的效率和性能方面的问题ext在写入文件内容的同时并没有同时写入文件的metadata(和文件有关的信息例如权限所有者以及创建和访问时间)换句话说Linux先写入文件的内容然后等到有空的时候才写入文件的metadata如果在写入文件内容之后但在写入文件的metadata之前突然断电了文件系统就会处于不一致的状态在一个需要大量文件操作的系统中(例如像Hotmail这样的免费的Web email)出现这种情况会导致很严重的后果日志文件系统可以帮助解决这个问题
假定你正在更新一个目录项(directory entry)你已经在这个巨大的目录项的第五个文件块(block)中改变了个文件项(file entry)当正在写这个文件块的时候突然间断电了这个文件块还没有写完也就是被损坏了
重新启动的时候Linux(就像其它的Unix)会运行一个叫做fsck(file system check)的程序扫描整个文件系统保证所有的文件块都被正确地分配或使用它将找到这个被损坏的目录项并试图修复它但是不能够保证fsck一定能够修复损坏修复不了是经常的事所以当出现上面那种情况目录项中所有的文件项可能会丢失也就造成文件的丢失
如果文件系统很大fsck扫描要费很长时间在一个有数十亿个文件的计算机上fsck可能要运行个小时以上在这段时间内系统是不可用的也就是导致了很长的当机时间日志文件系统可以避免这种情况
文件系统是怎样工作的?
文件系统通过为每个文件分配文件块的方式把数据存储在存储设备中这样就要维护每一个文件的文件块的分配信息而分配信息本身也要存在磁盘上DOS和Windows的用户可能还记得FAT这种文件系统吧不同的文件系统用不同的方法分配和读取文件块
有两种常用的文件系统的分配策略块分配(block allocation)和扩展分配(extent allocation)块分配当文件变大的时候每一次都为这个文件分配磁盘空间而扩展分配则是当某个文件的磁盘空间不够的时候一次性为它分配一连串连续的块
传统的Unix文件系统使用的块分配的机制提供了一个灵活而高效的文件块分配策略磁盘上的文件块根据需要分配给文件这样可以减少存储空间的浪费当一个文件慢慢变大的时候就会造成文件中文件块的不连续这就导致了过多的磁盘寻道时间当读取一个文件的时候有可能要随机而不是连续地读取文件块这样的效率很低
可以通过优化文件块的分配策略(尽可能为文件分配连续的块)来避免文件块的随机分配通过使用聪明的块分配策略可以实现块的连续分配这样就可以减少磁盘的寻道时间但是当整个文件系统的文件块的分配形成碎片的时候就再也不可能连续分配了
每一次当文件扩展的时候块分配的算法就要写入一些关于新分配的块所在位置的信息如果每一次文件扩展的时候只增加一个块那么就需要很多额外的磁盘I/O用来写入文件块的结构信息文件块的结构信息也就是上面说的metadatametadata总是一起同时地写入存储设备的这就意味着改变文件大小的操作要等到所有的metadata的操作都完成之后才能进行因此metadata的操作会显着地降低整个文件系统的性能
基于扩展(Extentbased)的分配方式
扩展分配方式一次性为文件分配很多连续的块当创建一个文件的时候很多文件块同时被分配当文件扩展的时候也一次分配很多块文件系统的metadata在文件创建的时候被写入当文件的大小没有超过所有已分配的文件块的大小就不用写入metadata(直到需要再分配文件块的时候)
这样可以优化磁盘寻道的方式可以成组地分配块有利于一次写一大批数据到存储设备中这样就可以减少SCSI设备写数据的时间
基于扩展分配的文件系统在读取顺序文件的时候有很好的性能因为文件块都是成组连续分配的但是如果I/O操作是随机的基于扩展分配的文件系统的好处就非常有限了例如当我们要连续地读取一个基于扩展分配的文件的时候我们只要读起始块号和文件长度就行了然后就可以连续地读取所有的文件块了这样在顺序读取文件的时候读metadata的开销就很小反之如果随机地读取文件我们就要先查找每一个所需块的块地址然后再读取块的内容这样就和块分配方式很象了
在ext文件系统中对写性能的增强是通过尽量延迟写的时间这样就能一次写一大批数据而不是每次写一小点随之而来的就是系统效率的提高同样当读的时候ext也是一次读取一整组的块也就是采用预读策略这样就能提高ext文件系统的读性能大量减少每次读取少量数据的I/O操作
文件块的组或块簇(block cluster)的大小是在编译的时候确定的怎样设定簇的大小不是这篇文章所要介绍的内容但是可以这么说簇的大小对文件系统的性能确实有很大的影响而且簇的大小也是文件系统设计的时候需要考虑的一个很重要的方面
象Veritas这样的扩展分配的文件系统和象ext这样的成簇写(writeclustering)的文件系统在默认情况下都使用字节的块而不用k字节的块如果ext用k而不是k字节的块大概会有%的性能提升但是为了减少被浪费的空间ext文件系统的设计者建议使用k字节的块
日志文件系统是怎样解决问题的?
先提醒你一下这节标题可能容易导致误解日志文件系统确实解决了上面提到的一些问题但是又带来了新问题
日志文件的设计思想是跟蹤文件系统的变化而不是文件系统的内容为了更好地解释这个问题下面我用ext文件系统和日志文件系统举一个例子
当我们改变文件testfile的内容的时候会出现什么情况?先假定testfile的inode有四个数据块用来保存testfile文件的数据块的块号分别为和(因为在和之间的块已经分配给其它文件了所以这些块不连续)当硬盘要先找到读两块在跳到再读两块才能读取整个文件假定你改变了第三块文件系统会读取第三块改变它然后重新写入第三块这一块还在这个位置如果你往文件中添加了一些内容就要从别的地方另外分配一些空余的块
如果在日志文件系统中情况就有所不同日志文件系统不会改变第块的内容它会把testfile的inode的一个拷贝和新的第三块保存到磁盘上在内存中的inode列表需要更新让testfile使用新的inode所有的变化添加和改变需要被记录到一个文件系统中被称为日志的那部分中去每隔一段时间文件系统在检查点(check point)回更新在磁盘上的inode并且释放文件中用不到的那些旧块(例如testfile文件最初的第三块)
在系统崩溃之后日志文件系统很快就能恢复它需要恢复的只是日志中记录下来的很少的几块当断电之后fsck只要用几秒钟的扫描时间
这就是我所说的解决了一些问题!
但是文件系统为得到额外的安全也是要付出代价的这就是系统开销每一次更新和大多数的日志操作都需要写同步这样就需要更多的磁盘I/O操作系统管理员就面临这样一个问题为了有一个更安全的文件系统值不值得牺牲一部分性能?
大多数系统管理员会根据实际情况作出决定没有必要把/usr目录放在日志文件系统上因为/usr目录大部分是只读的操作但是可以考虑把/var或包含email spool文件的目录放在日志文件系统上幸运的是在Linux系统中可以根据需要混合使用这些文件系统
日志文件系统还有一个问题就是更容易产生碎片因为它的文件分配方式与众不同很容易在文件系统中到处产生碎片ext文件系统也会产生碎片但是可能不会有这么严重每个月定期把文件系统备份到磁带中然后重新恢复不仅可以解决这问题而且可以检查备份/恢复的过程是否正确
想得到一些好处总是要付出一些代价的不是吗?
可供选择的Linux日志文件系统
当我写这篇文章的时候有两个日志文件系统还在开发有三个日志文件系统可供使用
SGI的xfs()日志文件系统和Veritas()的文件系统和卷管理(volume manager)这两个文件系统在五个月前就发布了但是现在还不能得到源代码SGI的xfs是基于Irix(SGI的Unix)上已经实现的xfsSGI已经宣布xfs为Open Source的软件
两个马上就可以得到的日志文件系统是reiserfs和IBM的jfs这两文件系统都是开放源代码的而且很多有天赋的人在开发这两个文件系统jfs(Journaled File System Technology for Linux)的开发者包括AIX(IBM的Unix)的jfs的主要开发者
在A