Linux運維學習 | Linux之父對文件系統發飆

Linux運維學習 | Linux之父對文件系統發飆

 

 

Linus 又發飆了,這一次是 ext4

 
 

 

如果你訂閱了 Linux Kernel 的 maillist,你一定發現最近 Linus 又爆粗口了,而這次的對象是 ext4 文件系統。

On Sun, Aug 6, 2017 at 12:27 PM, Theodore Ts'o <[email protected]> wrote:

>

> A large number of ext4 bug fixes and cleanups for v4.13



A couple of these appear to be neither cleanups nor fixes. And a lot

of them appear to be very recent.



I've pulled this, but if I hear about problems, ext4 is going to be on

my shit-list, and you'd better be a *lot* more careful about pull

requests. Because this is not ok.



Linus

而這已經不是 Linus 第一次對 ext4 文件系統表達不滿了。

盡管 ext4 文件系統已經發布了多年,也被廣泛應用于桌面及服務器,但關于 ext4 存在可能丟數據的 Bug 報告就一直沒有中斷過。例如在 2012 年的一封郵件中,Theodore Ts'o 報告了一次嚴重的 Bug,已經影響了部分 Linux 穩定版本的內核。

如果你持續關注文件系統或內核技術,你一定注意過這樣一篇文章:Fuzzing filesystem with AFL。Vegard Nossum 和 Quentin Casasnovas 在 2016 年將用戶態的 Fuzzing 工具 AFL(American Fuzzing Lop)遷移到內核態,并針對文件系統進行了測試。

Linux運維學習 | Linux之父對文件系統發飆

結果是相當驚人的。Btrfs,作為 SLES(SUSE Linux Enterprise Server)的默認文件系統,僅在測試中堅持了 5 秒鐘就掛了。而 ext4 堅持時間最長,但也僅有 2 個小時而已。

這個結果給我們敲響了警鐘,Linux 文件系統并沒有我們想象中的那么穩定。而事實上,在 Fuzz 測試下堅持時間長短僅僅體現出文件系統穩定性的一部分。數據可靠性,才是文件系統中最核心的屬性。然而 Linux 文件系統社區的開發者往往都把注意力放在了性能,以及高級功能的開發上,而忽略了可靠性。

今天,我們就帶大家回顧一下 Linux 文件系統的黑歷史,希望能夠警醒大家,不要過分相信和依賴文件系統。同時,在使用文件系統構建應用時,也需要采用正確的“姿勢”。

 

 

POSIX,一個奇葩的標準

 
 

 

談到 Linux 文件系統,不得不提到 POSIX(Portable Operating System Interface),這樣一個奇葩的標準。而開發者對于 POSIX 的抱怨,可謂是罄竹難書。

作為一個先有實現,后有標準的 POSIX,在文件系統接口上的定義,可謂是相當的“簡潔”。尤其當系統發生 crash 后,對于文件系統應有的行為,更是完全空白,這留給了文件系統開發者足夠大的“想象空間”。也就是說,如果一個 Linux 文件系統在系統發生崩潰重啟后,整個文件系統的內容都不見了,也是“符合標準”的。

而事實上,類似的事情確實發生過:在 2015 年,ChromeOS 的開發者曾報告了一個 ext4 的問題,有可能導致 Chrome 發生崩潰。而來自 ext4 開發者的回答是,“Working As Intended”

在歷史上,不斷有人嘗試給文件系統提供更加嚴謹的 Consistency(一致性)定義,尤其是 Crash-Consistency(故障后的一致性)。到目前為止,盡管 POSIX 也經歷了幾個版本,但關于文件系統接口的定義,還是那個老樣子。而 POSIX 標準,也是造成了文件系統各種問題的一個很重要的因素。關于各種一致性的定義,我們后面也會有文章專門進行介紹。

 

 

文件系統的黑歷史

 
 

文件系統一直有著光輝的發展歷史,也孕育了許多偉大的 Linux 內核貢獻者。從最早的 FFS,到經典的 ext2/ext3/ext4,再到擁有黑科技的 Btrfs,XFS,BCacheFS 等。

 

Linux運維學習 | Linux之父對文件系統發飆

然而軟件開發的過程,當然不是一帆風順的。威斯康辛大學麥迪遜分校的研究者曾在 FAST '13 上發表過一篇著名的論文《A Study of Linux File System Evolution》。文章對 8 年中,Linux 社區與文件系統相關的 5079 個 Patch 進行了統計和分析。從其數據中可以看出,有將近 40% 的文件系統相關的 Patch 屬于 Bugfix 類型。換句話說,每提交兩個 Patch,就有可能需要一個 Patch 用于 Bugfix。

Linux運維學習 | Linux之父對文件系統發飆

而文件系統的 Bug 數量并沒有隨著時間的推移而逐漸收斂,隨著新功能不斷的加入,Bug 還在持續不斷的產生。而 Bug 的集中爆發也往往源于大的功能演進。

Linux運維學習 | Linux之父對文件系統發飆

而從上圖中可以看出,在所有的 Bug 中,有接近 40% 的 Bug 可能導致數據損壞,這還是相當驚人的。

可以想象,在 Linux 文件系統的代碼庫中,還隱藏著許多 Bug,在等待著被人們發現。

哥倫比亞大學文件系統領域著名的專家 Junfeng Yang,曾經在 OSDI '04 上發表了一篇論文,該論文也是當年 OSDI 的最佳論文。在這篇論文中,Junfeng Yang 通過 FiSC,一種針對文件系統的 Model Checking 工具,對 ext3,JFS,ReiserFS 都進行了檢查,結果共發現了 32 個 Bug。而不同于 AFL,FiSC 發現的 Bug 大部分都會導致數據丟失,而不僅僅是程序崩潰。例如文章中指出了一處 ext3 文件系統的 Bug,該 Bug 的觸發原因是在通過 fsck 進行數據恢復時,使用了錯誤的寫入順序,在 journal replay 的過程中,journal 中的數據還沒有持久化到磁盤上之前,就清理了 journal,如果此時發生斷電故障,則導致數據永久性丟失。

 

 

對應用程序開發的影響

 
 

 

對于大部分應用程序開發者來說,并不會直接使用文件系統。很多程序員都是面向數據庫進行編程,他們的數據大多是存在數據庫中的。我們經常想當然的認為,數據庫的開發者理應會理解文件系統可能存在的問題,并繞過文件系統的 Bug,幫助我們解決各種問題。然而這只是一種僥幸心理罷了,由于文件系統過于復雜,標準不清晰,即使是專業的數據庫的開發人員,也往往無法避開文件系統中所有的問題。

以 LevelDB,我們最常用的一種單機 Key-Value Store 舉例。研究人員分別對 LevelDB 的兩個版本,1.10 和 1.15 進行了測試,分別發現了 10 個和 6 個不同程度的漏洞。其中 1.10 版本有 1 個漏洞可能導致數據丟失,5 個漏洞導致數據庫無法打開,4 個漏洞導致數據庫讀寫錯誤。而 1.15 版本分別有 2 個漏洞導致數據庫無法打開,2 個漏洞導致數據庫讀寫錯誤。

這些問題,大部分源自應用開發者對文件系統錯誤的假設。也就是說,他們以為文件系統可以保證的特性,而事實上并不能得到保證。而這些特性,也都是 POSIX 標準中未曾明確定義的。

這里我們舉個例子:

Append atomicity,追加寫原子性。

向文件中追加寫入,并不意味著是原子性的。如前文 ChromeOS 開發者遇到的 ext4 的問題,其根本原因,就是假設 ext4 文件系統是保證追加寫原子性的。在這封郵件中,開發者提供了一個可以復現問題的步驟。假設文件中已經有 2522 字節的數據,再追加寫入 2500 字節的數據,文件大小本應為 5022 字節。而如果在追加寫的過程中,遇到系統崩潰,在系統恢復后,文件的大小可能是 4096 字節,而非 5022 字節,而文件的內容,也可能是垃圾數據,無法被程序正確識別。

LevelDB 同樣也假設了文件系統具有追加寫的原子性,前面提到的一些漏洞就源于此。

而這僅僅是冰山一角。單單關于文件系統寫入數據的原子性,就有包括:單 sector 覆蓋寫,單 sector 追加寫,單 block 覆蓋寫,單 block 追加寫,多 block 追加寫等等。而對于不同類型的文件系統,甚至同一個文件系統的使用不同參數,對于原子性都可能具有不同范圍的支持。再考慮到 POSIX 提供的其他接口,包括 creat,rename,unlink,truncate 等等(關于這些接口背后的坑,我們后續將單獨寫文章介紹)。這使得開發應用系統,尤其是數據庫系統,變得非常復雜。

 

 

開發者的正確姿勢是什么

 
 

 

這里我們提供一些建議,希望能夠幫助大家盡量少的踩坑。

首先,對于大部分應用程序員來說,應盡可能選擇使用成熟的數據庫,而非直接操作文件。盡管如前文所說,在復雜的文件系統面前,數據庫也無法幸免于難,但數據庫開發者掌握的關于文件系統的知識,還是遠遠強于普通開發者的。數據庫也通常提供了數據恢復工具,以及備份工具。這避免了開發者重新造輪子,也極大的減輕了災難發生后可能帶來的影響。

而對于單機數據庫,分布式數據庫,以及分布式存儲的開發者來說,我們的建議是盡量避免直接使用文件系統,盡可能多的直接使用裸設備,這避免了很多可能引起問題的接口,例如 creat,rename,truncate 等。例如 SmartX 在設計和實現分布式存儲時,就直接使用裸設備。

如果必須要使用文件系統,也要使用盡量簡單的 IO 模型,避免多線程,異步的操作。同時,一定要在設計的過程中,把對于文件系統操作的模型抽象出來,并畫成步驟圖,這里我們推薦 draw.io,一個非常不錯的免費畫圖工具。要假設每一個步驟都可能失敗,每一個步驟失敗后,都可能產生垃圾數據,要提前設計好數據校驗以及處理垃圾數據的方式。如果步驟之間有存在依賴關系,一定要在執行下一步之前,調用 fsync(),以保證數據被持久化到磁盤中。

最后,設計和實現完成后,在單元測試和集成測試的過程中,也一定要增加故障測試。例如在單元測試中,通過 mock 的方式模擬 IO 故障,在集成測試中,可以加入隨機 kill 進程,隨機重啟服務器的測試用例,也可以通過 dm-delaydm-flakey 等工具進行磁盤故障模擬。

 

 

總結

 
 

 

看了這么多黑歷史,真的是三觀都毀掉了。而事實上,我們每天確實都生活在這些危機中。

這里要強調的是,我們并不是想詆毀 Linux 文件系統,相反,我們非常感謝 Linux 內核開發者在文件系統方面做出的貢獻。但同時,由于系統的復雜度所帶來的嚴重問題也是無法回避的。在 Linux 文件系統的代碼中,必然還存在著很多未被發現的嚴重 Bug,開發者和研究人員也從來沒有停止過尋找 Bug 的努力。而隨著新功能不斷地加入,新的 Bug 也在不斷的產生。我們多一些這方面的思考和謹慎,并不是什么壞事。

感謝大家的觀看!

作者:張凱(Kyle Zhang) ,SmartX 聯合創始人 & CTO。SmartX 擁有國內最頂尖的分布式存儲和超融合架構研發團隊,是國內超融合領域的技術領導者。

來源:SmartX知乎賬號

鏈接:https://zhuanlan.zhihu.com/p/28828826

 

 


 

————廣告時間————

《馬哥Linux云計算及架構師》課程,由知名Linux布道師馬哥創立,經歷了8年的發展,聯合阿里巴巴、唯品會、大眾點評、騰訊、陸金所等大型互聯網一線公司的馬哥課程團隊的工程師進行深度定制開發,課程采用 Centos7.2系統教學,加入了大量實戰案例,授課案例均來自于一線的技術案例。

開課時間:11月06號

Linux運維學習 | Linux之父對文件系統發飆Linux運維學習 | Linux之父對文件系統發飆課程咨詢請長按即可咨詢Linux運維學習 | Linux之父對文件系統發飆Linux運維學習 | Linux之父對文件系統發飆

Linux運維學習 | Linux之父對文件系統發飆

Linux運維學習 | Linux之父對文件系統發飆

 

相關新聞

聯系我們

400-080-6560

在線咨詢:點擊這里給我發消息

郵件:[email protected]

工作時間:周一至周日,09:00-18:30

QR code
云南快乐10分开奖直播