有一天,身体问心:“我要是痛了,医生会给我治,你痛了谁给你治啊?”于是心说:“我只能自己给自己治。”也许是因为这样,每个人都有治疗自己心中伤痛的方法。喝酒、唱歌、发火、发疯、找人说话、跑马拉松,等等,等等。当年我上大学时,我们同宿舍的二哥就是喜欢跑马拉松,结果就有一个女孩天天看着他跑,至于接下来怎么样啦,我想你懂的。当然,还有人会逃避这种心里的痛,不过这是我认为最差的方法。我的方法,就是站在讲台上发疯,给大伙讲一些伪技术。一些比较“邪性”的东西。 话说有一种感动,叫内牛满面,有一种文件系统,根本不在磁盘上。这种文件系统就是大名顶顶的ram-based filesystem。实际上,在Linux系统中,/dev、/proc、/sys目录里面的内容与硬盘是没有半毛钱关系的。那么这些玩意到底有什么用,怎么用,在听我白乎完以后,最好再去看看内核源代码中的一些文档。要知道文档这种东西,真正读起来就嫌少了。至于你信不信,反正我是信了。 在这一章中只是讲这些内容我是不会尽兴的,我还会追加一些譬如tmpfs、debugfs、relayfs等。虽然这似乎是一些很冷的话题,对于很多人来说,它们的受欢迎程度,肯定是既赶不上陈冠希老师的摄影作品,也赶不上苍井空老师的启蒙课程。不过人在江湖身不由己,因为工作的原因,为了提高自己抓紧升P ,你不得不来看一看,扩大一下自己的知识面,即便在工作中用不到,以后拿来泡妞或许也能管点用处。有诗云:“海上本无花,因风而起;心中本无恨,因爱而生……” 9.1 日志和ReiserFS 为了追根溯源、舍末逐本,在这一章真正开始之前,我先要脱离一下主题,以便为接下来的行程做好准备。我将会涉及两个对于Linux开发社区非常重要的主题——日志和“ReiserFS后”的设计理念。 日志一直都是非常重要的,就像没有韩局长的日记一样(请作者解释韩局长的日记是神马东东),没有它,我们的生活就缺少了很多茶余饭后的谈资。日志一直是人们长期期待的技术,从Linu x 2.4以后出现了。即使你对日志已有所掌握,我还是希望我有关日志的介绍能够成为一个好的模型,以用来向其他人解释这项技术,或者你就当它是泡妞的工具吧,因为与众不同也是吸引女孩子注意的基本素质。不管你是不是这么认为的,反正我是这么做的,也达到了目的。 本节的后面我会讲解一下ReiserFS的设计理念。希望让大家能够认清一个事实,就是新的系统并不是只为了做同样的事情比老的系统快一点,还应该允许我们用以前完全不可能的方法来处理事情。作为一名人民的好干部,如果希望被惦记,可以学我们的郑书记,将自己和蔼可亲的光辉形象搬上台历;作为一名有梦想有追求而又不知道如何出名的人,你可以参考芙蓉和凤姐;作为一个Linux爱好者,又想成为IT行业中一名能够被人记住的工程师,我们就应该牢记这一点——用以前完全不可能的方法来处理事情。 9.1.1 理解日志 1. 元数据 电影《色戒》告诉我们,床戏是用身体来诠释爱情的;而文件系统则教导我们,元数据就是诠释数据的数据。有点绕,较为通俗的解释是这样的:作为文件系统,一定要提供存储、查询和处理数据的功能。那么,文件系统就保存了一个内部数据结构,使得这些操作成为可能。这个内部数据结构,就是元数据,它为文件系统提供特定的身份和性能特征。 元数据对于99.99%的人来说,都是不必关心的,因为元数据是专门交给文件系统的驱动程序使用的,平时根本碍不着你什么事儿。不过有一点很重要:要想文件系统的驱动程序好好干活,它就得轻松愉快地找到元数据。要求有三:一要合理、二要一致、三要无干扰。否则的话,驱动程序就没法理解元数据,也操作不了,那么你就只能跟你的文件说拜拜了。 这里啰嗦几句。文件系统是文件系统,文件系统的驱动程序是文件系统的驱动程序,不是一码事,就好比人是人他妈生的,妖是妖他妈生的。那些大家耳熟能详的ext2、ext3等,实际上叫文件系统类型。可以这样理解:文件系统是项目,类型是方案,驱动程序就是执行人。虽然不能混淆是非,但是平时跟大家说文件系统,上述三点一般都代表了,不必太较真儿。 2. fsck 既然文件系统驱动程序那么娇贵,就得有人伺候它,给它请个保姆。这个保姆就是fsck。fsck确保文件系统驱动程序要用的元数据是干净的,但是有时候也不会特别周到。 它具体是怎么伺候文件系统驱动的呢?是这样的:每次Linux启动,在没有挂接任何文件系统的时候,都会启动fsck扫描一下/etc/fstab文件中列出的所有本地文件系统;每次Linux关闭,它要把还在内存中的被称之为页面缓存或磁盘缓存中的数据转送到磁盘,还要保证把已经挂接的文件系统卸载干净。这套流程说简单了就是:fsck要检查那些即将被挂接的文件系统,之前是被卸载干净了的,然后做出一个合理的假设——所有元数据都是干净的,没问题。 3. fsck的问题 不过话分两头说,当年陈冠希老师对自己的摄影作品也是细心呵护,珍爱有佳,可是偏偏就有意外发生。对于陈老师来说,这个意外对他本人或许还给自己“增光”不少,好多人羡慕得不得了。可是对于文件系统来说,塞翁一旦失马,马还回得来吗? 一般是这样的:当Linux遇到异常关机(比如断电、kernel panic或者管理员有点蛋疼),重启后fsck就会发现有文件系统没卸载干净,对应的元数据可能不干净,已经出了问题。于是乎开始奋力苦干,全面审查元数据,修正一切可以修复的错误,文件系统又可以正常使用了。从这点来看,似乎“马”是回来了。 星星还是那颗星星,月亮还是那个月亮,可是“马”还是那匹“马”吗?前面说过,fsck是修正一切可以修复的错误,那么不能修正的怎么办呢?丢掉——这似乎很残忍,但是也只能丢掉,否则就会像手臂上化了脓的伤口,如果不切掉那块肉,以后失去的可能是整个手臂。其实还有远比这个要严重的,fsck要扫描全部元数据。这显然不是技巧活儿,是需要动蛮力的。少则花几分钟,多则几小时。如果这事儿发生在任务繁重的数据中心,标准的fsck过程就不是在帮你了,那是害你不死啊! 4. 日志 土豆会有的,面包会有的,牛奶也会有的,好运更是会有的。日志——一个更好的解决方案很快就有了。 韩局长的日记里记录了他对女下属都干了些什么,文件系统的日志记录了它对元数据都干了些什么。不同的是,韩局长的日记不单写在纸上,还放到网络里给我们品味人生,文件系统的日志只是放在自己磁盘的分区中,让fsck放行的。 具体操作是这样的:元数据出现问题后,fsck在遇到有日志的文件系统时要做的事情就是放行,接下来由文件系统驱动负责按照日志里面的记载去恢复元数据。具体怎么恢复其实跟fsck的方法类似,该扔的还得扔。不过时间可就快多了,毕竟这是技巧活不是体力活。实际结果是,使用日志文件系统修复上百GB的元数据也只是眨一下眼时间。 说到这里有人会问。日志只是解决了修复时间的问题,那数据丢失了怎么办?那我告诉你,只能凉拌了。一些建议是: 给你的服务器弄个不间断电源; 选择一个公认的稳定的内核版本; 不要让蛋疼的管理员碰你的服务器。 9.1.2 ReiserFS——卓越的小文件性能与渺茫的未来 说完日志,我们开始说ReiserFS。选择ReiserFS说事儿不单单是因为它是众多日志型文件系统之一,还有它的设计目的也很特别。它的设计者Hans Reiser的想法是:一个最好的文件系统,不单能够管理好用户的文件,还能够适应环境干点别的,比如代替数据库。 1. 小文件性能 那么怎么才能让文件系统能够适应环境呢?ReiserFS就干了这么一件事儿——关注小文件的性能。因为我们常见的如ext2、ext3等文件系统一遇到小文件就傻了,这就迫使开发人员在处理比较零碎的数据时,不得不考虑采用数据库或其他手段来获取他们想要得到的性能指标。如此反复下去,问题就来了,在漫漫的历史长河中,这种“针对问题进行创作”的方式怂恿了代码的膨胀,还弄出了一大堆不知所云的带有特殊目的的API。肮脏的社会,悲催的现实的本源就是那些不合理的制度。 柿子咱们挑软的捏,就拿ext2开刀,看看它是怎样把代码肚子搞大的。ext2比较擅长的是存储大量大小在20K以上的文件,但是你要让它帮你存储20000个50字节左右的文件,ext2能不能hold住不知道,你肯定是hold不住了。不但性能急剧下降,存储效率也是飞流直下三千尺。因为ext2的最小存储单元是1k或4k,即便你只存储1个字节,也得占用1k或4k。这样换算下来,20000×1k=20M或20000×4k=80M,而你实际需要的只有20000×50=1M,存储效率只有5%,甚至只有1.25%。如果你头脑还清醒的话,直觉就会告诉你不应该在文件系统上存储这么多小文件。这种经历慢慢地就会成为经验,你也会告诉其他人这么干是不行的,应该使用数据库或者自己想办法。不管怎么样,你都要付出很多额外的代码。 那么ReiserFS来了,问题就不这样了。ReiserFS处理小文件的性能好得不得了。好到什么程度呢?ReiserFS在处理小于1k的文件时,比ext2快8到15倍。更妙的是,处理大于1k的文件的时候,也不会有什么性能损失。ReiserFS大多数情况下都要好于ext2,处理小文件是它闪光的地方。这个时候你的经验就不管用了,不过也轻松多了。放弃数据库,告别讨厌的数据库访问代码,你要做的就是读写文件。当你用过之后会很惊讶地喊出:原来可以这么简单呀。 2. ReiserFS技术 ReiserFS的小文件性能如此突出,那么它是怎么练就这种绝世武功的呢? 原来ReiserFS采用了一种叫做B*树的数据结构。这是一种全新的经过特殊优化的树形数据结构。ReiserFS用它来组织元数据,相当于整个磁盘分区是一个B*树。 这里说明一下B*树的概念。一般专业学过计算机应用的,多少都会接触点数据结构这个东西。不管是老师讲的,还是道听途说来的,链表、堆栈、树、图这些大体上都是了解的。作为“树”这种数据结构,书上说得最多的就是二叉树。但凡涉及二叉树,说得最多的就是二分查找,因为效率高嘛(100万个数据,只要20几次比较就能找到所要的数据)。在二分查找领域中,利用“树”来说事儿的普遍有二叉查找树、平衡二叉查找树,乃至AVL树和红黑树。这里大红大紫的当推红黑树,因为C++的STL(标准模板库)中的map容器就是使用的这种数据结构。乃至后来Java中的map,苹果Objective-C中的字典也使用这种数据结构。只要你是程序员,就离不开它。因为在基于内存这种介质的二分查找算法中,红黑树是最稳定的。那么基于磁盘介质上的高效查找(注意这里没有说二分)算法呢?答案是B树,正如很多人了解到的“B-”树。其实世界上本没有“B-”树这个东西,只是叫的人多了,它便成为了“B-树”。究其原因是某些人翻译得不负责任,大多数外国文献中使用B-tree来说明,就翻译成“B-树”了。实际上B-tree说的就是B树。B树是针对磁盘或其他存储介质而设计的一种多叉平衡查找树。与红黑树类似,不同的是,B树节点可以有很多子女,从几个到几千个。但是马上有人就会站起来反驳,这跟红黑树差别也太大了吧,怎么能说类似呢?是这样的,一棵含有n个节点的B树的高度也跟红黑树一样,也是O(logn),所以B树可以在O(logn)时间内,实现插入、删除等动态集合操作。不过由于分支因子比较大,实际的B树要比红黑树的高度小很多。不过实际的文件系统并不是用B树,它们大多使用的是B+树。B+树是B树的一个变形,在降低磁盘读写代价的同时,提高了查询效率的稳定性。绕了这么久,终于开始说一下B*树了,不过你可能会很失望,就是简单一句:B*树是B+树的变形,B*树分配新节点的概率比B+树要低,空间利用率更高。 利用B*树的特性,ReiserFS允许一个目录下可以容纳10万个子目录,从这一点看,就已经基本上排除了文件系统设计上的人为约束了。另外一个好处是,ReiserFS可以根据需要动态的分配索引,这样也就省去了固定索引,没有附加空间,提高了存储效率。ReiserFS的与众不同之处还有,不使用固定大小的数据块分配存储空间,采用精确分配原则,这样就不会有磁盘空间的浪费。而且ReiserFS还提供了一种叫以尾文件为中心的特殊优化。什么是尾文件呢?就是比系统文件块小的文件或文件的结尾部分。为了提高性能,ReiserFS可以利用B*树的叶节点存储文件,从而不用把数据先保存在其他地方,然后再指向它。 ReiserFS实际上做了两件事。第一,显著提高小文件性能,把文件数据和索引信息放在一起,大多数情况下只需要一次磁盘I/O就能搞定;第二,压缩尾文件,这样可以节省大量磁盘空间,一般可以比ext2文件系统多存储6个百分去点的数据。别小看这6%,当磁盘足够大,文件足够多时,这方面的性能完全可以用叹为观止来形容。 不过我一向不喜欢把话说死,其实ReiserFS的尾文件压缩是以牺牲速度为代价的。有鉴于这个原因,ReiserFS的作者们提供了一个开关,可以让管理员关掉尾文件压缩功能,可以让管理员根据实际使用情况,酌情考虑是要速度还是存储能力。 3. 渺茫的未来 对于大多数男人是只知道女人的底裤在那里,却不知道女人的底线在哪里,总是想挑战女人的极限;对于我们德高望重的Hans Reiser应该取反,因为他的女人一直在挑战他的极限,结果……耗子急了咬了猫。2008年4月28日,被加利福尼亚州奥克兰法庭认定其杀妻罪名成立,判决15年监禁。从此ReiserFS的开发就基本处于停滞状态。虽然有开发者主动挺身而出,但是主创灵魂已身陷囹圄,ReiserFS的命运一直蒙着一层阴影。乃至一度大力推广ReiserFS的Novell公司都开始反水,在2006年10月12日宣布在未来的SUSE Linux Enterprise版本中不再使用ReiserFS作为默认文件系统,改用ext3。即便如此,ReiserFS依然是Linux系统中最优秀的文件系统之一,而且现在依然是可以使用的。 9.1.3 应用实战 到目前为止,Linux的主线版本已经升级到了3.8,但是很不幸的是,由于ReiserFS v4一直没有被纳入Linux的主线,我们不得不通过内核补丁来一尝ReiserFS v4的朱唇,到本书截稿之前支持的最高内核版本是3.7。 要使用ReiserFS v4还是有点小麻烦的,具体步骤是这样的: 1. 准备内核源代码。这年头怎么都得是2.6.xx的吧? 2. 下载一个对应您内核版本的补丁。reiser4-for-2.6.xx.patch.gz。 3. 下载ReiserFS v4的工具包。libaal-1.0.5.tar.gz和reiser4progs-1.0.6.tar.gz。 4. 安装libaal。一个工具库,提供个哈希表,位操作什么的。 5. 安装reiser4progs。这是用来使用ReiserFS分区的工具。包括debugfs.reiser4、fsck.reiser4、measurefs.reiser4和mkfs.reiser4。debugfs.reiser4用来调试ReiserFS的,这个工具利用了我们后面要讲解的debugfs;fsck.reiser4用来检测和修复ReiserFS磁盘分区的,fsck我们前面已经介绍过了;measurefs.reiser4用于度量ReiserFS磁盘分区,比如查看磁盘碎片;mkfs.reiser4就是格式化工具了。 6. 给内核源代码打补丁。一般执行的操作就是: gzip -cd ../reiser4-for-2.6.xx.patch.gz | patch -p1 注意:执行这步操作要确保你在内核源代码的根目录下。 7. 配置、编译和安装内核。 8. 使用新内核重新启动。 重新启动后,你就拥有ReiserFS了。接下来要做的就是找一个分区,使用mkfs.reiser4进行格式化,使用mount命令挂载就好了。 9.1.4 小结 我讲这些并不是想让大家如何深刻的理解日志、ReiserFS乃至什么B*树。就好比女人如画,不同的画中有不同的风景,Linux也是如此,左看右看上看下看,角度不同,风景各异。再一次重复之前说的话:用以前完全不可能的方法来完成事情。日志和ReiserFS不正是对这句话很好的诠释吗? 接下来我们开始进入正题,Linux的特种文件系统!