最近12個月以來,Linux已經鞏固了其作為服務器操作系統的地位。就像集群(cluster)對於企業級的應用很重要那樣,日志文件系統(journaling file system)也是同樣重要的。 為什麼日志文件系統很重要呢?它是怎樣工作的呢?有哪些日志文件系統可以用於Linux? 日志文件系統比傳統的文件系統安全,因為它用獨立的日志文件跟蹤磁盤內容的變化。就像關系型數據庫(RDBMS),日志文件系統可以用事務處理的方式,提交或撤消文件系統的變化。 Ext2不能滿足要求 盡管Linux可以支持種類繁多的文件系統,但是幾乎所有的Linux發行版都用ext2作為默認的文件系統。Linux可以支持的文件系統有:FAT、VFAT、HPFS(OS/2)、NTFS(Windows NT)、Sun的UFS,等等。 ext2的設計者主要考慮的是文件系統的效率和性能方面的問題。ext2在寫入文件內容的同時並沒有同時寫入文件的meta-data(和文件有關的信息,例如:權限、所有者以及創建和訪問時間)。換句話說,Linux先寫入文件的內容,然後等到有空的時候才寫入文件的meta-data。如果在寫入文件內容之後但在寫入文件的meta-data之前,突然斷電了,文件系統就會處於不一致的狀態。在一個需要大量文件操作的系統中(例如,像Hotmail這樣的免費的Web e-mail),出現這種情況會導致很嚴重的後果。日志文件系統可以幫助解決這個問題。 假定你正在更新一個目錄項(Directory entry)。你已經在這個巨大的目錄項的第五個文件塊(block)中改變了23個文件項(file entry)。當正在寫這個文件塊的時候突然間斷電了,這個文件塊還沒有寫完,也就是被損壞了。 重新啟動的時候,Linux(就像其它的Unix)會運行一個叫做“fsck”(file system check)的程序,掃描整個文件系統,保證所有的文件塊都被正確地分配或使用。它將找到這個被損壞的目錄項並試圖修復它,但是不能夠保證fsck一定能夠修復損壞。修復不了是經常的事。所以,當出現上面那種情況,目錄項中所有的文件項可能會丟失,也就造成文件的丟失。 如果文件系統很大,fsck掃描要費很長時間。在一個有數十億個文件的計算機上,fsck可能要運行10個小時以上。在這段時間內,系統是不可用的,也就是導致了很長的當機時間。日志文件系統可以避免這種情況。 文件系統是怎樣工作的? 文件系統通過為每個文件分配文件塊的方式把數據存儲在存儲設備中。這樣就要維護每一個文件的文件塊的分配信息,而分配信息本身也要存在磁盤上。DOS和Windows的用戶可能還記得FAT這種文件系統吧。不同的文件系統用不同的方法分配和讀取文件塊。 有兩種常用的文件系統的分配策略:塊分配(block allocation)和擴展分配(extent allocation)。塊分配當文件變大的時候每一次都為這個文件分配磁盤空間,而擴展分配則是當某個文件的磁盤空間不夠的時候,一次性為它分配一連串連續的塊。 傳統的Unix文件系統使用的塊分配的機制提供了一個靈活而高效的文件塊分配策略。磁盤上的文件塊根據需要分配給文件,這樣可以減少存儲空間的浪費。當一個文件慢慢變大的時候,就會造成文件中文件塊的不連續。這就導致了過多的磁盤尋道時間,當讀取一個文件的時候有可能要隨機而不是連續地讀取文件塊,這樣的效率很低。 可以通過優化文件塊的分配策略(盡可能為文件分配連續的塊)來避免文件塊的隨機分配。通過使用聰明的塊分配策略,可以實現塊的連續分配。這樣就可以減少磁盤的尋道時間。但是,當整個文件系統的文件塊的分配形成碎片的時候,就再也不可能連續分配了。 每一次當文件擴展的時候,塊分配的算法就要寫入一些關於新分配的塊所在位置的信息。如果每一次文件擴展的時候只增加一個塊,那麼就需要很多額外的磁盤I/O用來寫入文件塊的結構信息。文件塊的結構信息也就是上面說的meta-data。meta-data總是一起同時地寫入存儲設備的,這就意味著改變文件大小的操作要等到所有的meta-data的操作都完成之後才能進行。因此,meta-data的操作會顯著地降低整個文件系統的性能。 基於擴展(Extent-based)的分配方式 擴展分配方式一次性為文件分配很多連續的塊。當創建一個文件的時候,很多文件塊同時被分配;當文件擴展的時候,也一次分配很多塊。文件系統的meta-data在文件創建的時候被寫入,當文件的大小沒有超過所有已分配的文件塊的大小,就不用寫入meta-data。(直到需要再分配文件塊的時候) 這樣可以優化磁盤尋道的方式,可以成組地分配塊,有利於一次寫一大批數據到存儲設備中,這樣就可以減少SCSI設備寫數據的時間。 基於擴展分配的文件系統在讀取順序文件的時候有很好的性能,因為文件塊都是成組連續分配的。但是,如果I/O操作是隨機的,基於擴展分配的文件系統的好處就非常有限了。例如,當我們要連續地讀取一個基於擴展分配的文件的時候,我們只要讀起始塊號和文件長度就行了。然後,就可以連續地讀取所有的文件塊了,這樣在順序讀取文件的時候,讀meta-data的開銷就很小。反之,如果隨機地讀取文件,我們就要先查找每一個所需塊的塊地址然後再讀取塊的內容,這樣就和塊分配方式很象了。 在ext2文件系統中,對寫性能的增強是通過盡量延遲寫的時間,這樣就能一次寫一大批數據而不是每次寫一小點。隨之而來的就是系統效率的提高。同樣,當讀的時候,ext2也是一次讀取一整組的塊,也就是采用預讀策略。這樣就能提高ext2文件系統的讀性能,大量減少每次讀取少量數據的I/O操作。 文件塊的組或塊簇(block cluster)的大小是在編譯的時候確定的。怎樣設定簇的大小不是這篇文章所要介紹的內容。但是,可以這麼說,簇的大小對文件系統的性能確實有很大的影響,而且簇的大小也是文件系統設計的時候需要考慮的一個很重要的方面。 象Veritas這樣的擴展分配的文件系統和象ext2這樣的“成簇寫”(write-clustering)的文件系統,在默認情況下都使用512字節的塊而不用1k字節的塊。如果ext2用4k而不是1k字節的塊,大概會有20%的性能提升。但是,為了減少被浪費的空間ext2文件系統的設計者建議使用1k字節的塊。 日志文件系統是怎樣解決問題的? 先提醒你一下:這節標題可能容易導致誤解。日志文件系統確實解決了上面提到的一些問題,但是又帶來了新問題。 日志文件的設計思想是跟蹤文件系統的變化而不是文件系統的內容。為了更好地解釋這個問題,下面我用ext2文件系統和日志文件系統舉一個例子: 當我們改變文件“test.file”的內容的時候會出現什麼情況?先假定“test.file”的inode有四個數據塊。用來保存“test.file”文件的數據塊的塊號分別為3110、3111、3506和3507(因為在3111和3506之間的塊已經分配給其它文件了,所以這些塊不連續)。當硬盤要先找到3100,讀兩塊,在跳到3500,再讀兩塊,才能讀取整個文件。假定你改變了第三塊,文件系統會讀取第三塊,改變它,然後重新寫入第三塊,這一塊還在3506這個位置。如果你往文件中添加了一些內容,就要從別的地方另外分配一些空余的塊。 如果在日志文件系統中,情況就有所不同。日志文件系統不會改變第3506塊的內容,它會把“test.file”的inode的一個拷貝和新的第三塊保存到磁盤上。在內存中的inode列表需要更新,讓“test.file”使用新的inode。所有的變化、添加和改變需要被記錄到一個文件系統中被稱為“日志”的那部分中去。每隔一段時間,文件系統在“檢查點”(check point)回更新在磁盤上的inode,並且釋放文件中用不到的那些舊塊(例如:“test.file”文件最初的第三塊)。 在系統崩潰之後,日志文件系統很快就能恢復。它需要恢復的只是日志中記錄下來的很少的幾塊。當斷電之後,“fsck”只要用幾秒鐘的掃描時間。 這就是我所說的解決了一些問題! 但是,文件系統為得到額外的安全也是要付出代價的,這就是系統開銷。每一次更新和大多數的“日志”操作都需要寫同步,這樣就需要更多的磁盤I/O操作。系統管理員就面臨這樣一個問題:為了有一個更安全的文件系統值不值得犧牲一部分性能? 大多數系統管理員會根據實際情況作出決定。沒有必要把“/usr”目錄放在日志文件系統上因為“/usr”目錄大部分是只讀的操作。但是,可以考慮把“/var”或包含e-mail spool文件的目錄放在日志文件系統上。幸運的是在Linux系統中可以根據需要混合使用這些文件系統。 日志文件系統還有一個問題就是更容易產生碎片。因為它的文件分配方式與眾不同,很容易在文件系統中到處產生碎片。ext2文件系統也會產生碎片但是可能不會有這麼嚴重。每個月定期把文件系統備份到磁帶中然後重新恢復,不僅可以解決這問題,而且可以檢查備份/恢復的過程是否正確。 想得到一些好處,總是要付出一些代價的,不是嗎? 可供選擇的Linux日志文件系統 當我寫這篇文章的時候,有兩個日志文件系統還在開發,有三個日志文件系統可供使用。 SGI的xfs(http://oss.sgi.com/projects/xfs/)日志文件系統和Veritas(www.veritas.com)的文件系統和卷管理(volume manager)。這兩個文件系統在五個月前就發布了,但是現在還不能得到源代碼。SGI的xfs是基於Irix(SGI的Unix)上已經實現的xfs。SGI已經宣布xfs為Open Source的軟件。 兩個馬上就可以得到的日志文件系統是reiserfs和IBM的jfs。這兩文件系統都是開放源代碼的而且很多有天賦的人在開發這兩個文件系統。jfs(Journaled File System Technology for Linux)的開發者包括AIX(IBM的Unix)的jfs的主要開發者。 在AIX上,jfs已經經受住了考驗。它是可靠、快速和容易使用的。Reiserfs應用了一些新的技術,例如,統一名字空間(unified name space),是非常有前途的(Namesys)可以參考。 有一些Linux的發行版已經包括了reiserfs文件系統,作為安裝時的可選項。SuSE 6.4 就很容易使用reiserfs文件系統。reiserfs的最新版是3.5.12,經過測試reiserfs的基准測試的結果是很激動人心的。這個測試使用“postmark”基准測試,50,000個事務處理20,000個文件。結果是: Sun E450 1 GB, Solaris 2.6, and vxfs (Veritas) file system: 22 transactions/second Sun E450 1 GB, Solaris 2.6, and UFS file system: 23 transactions/second Dual P-III, 1 GB Linux 2.2.13, standard ext2: 93 transactions/second Dual P-III, 1 GB Linux 2.2.13, reiserfs 3.5.5 journaling beta: 196 transactions/second Dual P-III, 1 GB Linux 2.2.13, reiserfs 3.5.5 journaling beta, mount options notail, genericread: 847 transactions/second (Sun的計算機用的是barracuda硬盤,x86的計算機用的是cheeta硬盤) 還有一個日志文件系統是jfs。jfs還沒有被任何Linux發行版采用,因為它現在的版本是0.7。但是,jfs進展得很快。本文的作者已經加入jfs項目現在是jfs FAQ的維護者。 reiserfs和jfs都非常容易安裝。下載完jfs的軟件包之後,還有下面幾個步驟要完成: 1) 解壓jfsXXX.tar.gz。 2) 軟件帶有內核(2.2.14、2.2.15和2.3.99)的補丁。把補丁拷貝到內核源代碼的目錄,通常在“/usr/src”。把補丁打到內核上,用這個命令: root@ maguro /usr/src # patch -p0 3) 重新編譯內核 root@ maguro /usr/src # make menUConfig; make dep; make clean; make bzImage; make modules 安裝reiserfs的步驟和上面類似: 1) 下載軟件包。 2) 把補丁拷貝塔內核源代碼所在的目錄,通常在“/usr/src”,給內核打補丁: root@ maguro /usr/src # zcat linux-2.2.11-reiserfs-3.5-patch.gz patch -p0 3) 編譯內核。 4) 用下面命令生成reiserfs文件系統: root@ maguro /usr/src # /linux/fs/reiserfs/utils/mkreiserfs /dev/hda2 另一個選擇 日志文件系統的另一個選擇是ext2的後繼者ext3fs文件系統。ext3fs文件系統正在Linux內核黑客Stephen Tweedie的領導下開發。 ext3fs還處於beta測試階段,就像reiserfs和jfs,但是它工作得很好。Stephen預計2000年夏天可以正式發布ext3fs。ext3fs最大的優點是向下兼容ext2。而且ext3fs還支持異步的日志,這意味著它的性能可能還比ext2好。 安裝ext3fs和安裝jfs和reiserfs類似。從這下載補丁:FTP://ftp.uk.linux.org/pub/linux/sct/fs/jfs。 就像reiserfs,ext3fs可能不久就會成為標准Linux內核的一部分,可能是2.4版的Linux內核。