Crash?! 軟件崩潰后的數據一致性
在馮 · 諾依曼的計算機體系結構中,數據的讀寫是最基本的任務之一。強一致性這種簡單直觀的方法對于程序員來說是最容易理解的,但是一些讀寫一致性較弱的模型被廣泛使用,這種方法提高了系統性能,但是代價是使系統行為更加復雜和容易出錯。同時,帶來了另一個問題,在系統crash時能否正確地恢復數據的讀寫呢?
許多應用程序都依賴于特定的文件系統實現,因此當在不同的文件系統或不同的配置上運行時,在系統崩潰后很容易出現意外的行為。
為了確保系統崩潰后的數據一致性,開發人員一般需要創建一個數據更新協議,即仔細構建的系統調用序列(例如文件寫入、重命名和其他文件系統調用) ,以可恢復的方式更新底層文件和目錄。因此,應用程序的正確性本質上取決于這些系統調用對系統崩潰的語義(即文件系統的崩潰行為)。然而,在所有應用程序中使用單一更新協議實現是不切實際的,可能取決于性能特征,例如,有些應用可能以順序的磁盤 i/o 為目標,并且更喜歡不涉及尋求文件差異的更新協議。數據更新協議的選擇還取決于可用性特征,也與應用程序的并發機制及其數據結構所使用的格式有著內在的聯系。
潛意識中的認同
在系統崩潰時,應用程序可以依賴的是什么樣的文件系統呢?
我們的潛意識中是這樣認為的,在系統崩潰時,磁盤上已經存在的信息(文件數據、目錄條目、文件屬性等等)會被保存下來,除非有人明確地發出影響它的操作。文件系統中的 fsync ()和類似的數據結構保證在調用返回時文件的數據在存儲設備上。
但是,在fsync ()中有一個細微之處,那就是關于“存儲設備”的定義: 在 fsync ()將信息發送到磁盤后,它可能駐留在磁盤緩存中,因此在系統崩潰時可能丟失,只能希望操作系統能夠提供了特定方案來盡其所能地刷新磁盤緩存。因為您可能在一個假的硬盤驅動器上運行,所以沒有任何承諾。另外,文件的目錄條目和文件本身是獨立的實體,可以分別發送到磁盤,一個文件的 fsync ()并不意味著其他方面的持久性。
文件系統的崩潰行為
一般地,應用程序崩潰后的數據一致性恢復取決于文件系統錯綜復雜的崩潰行為。關于文件系統的崩潰行為存在著兩個誤區:
誤區1 :POSIX 定義了崩潰行為
POSIX 定義了類 unix 操作系統導出的標準文件系統接口(打開、關閉、讀取和寫入) ,并且對于構建可移植應用程序至關重要。因此,人們可能認為 POSIX 要求文件系統對崩潰有一個合理且明確定義的響應,例如,將目錄操作按順序發送到磁盤。
誤區2: 文件系統按順序更新元數據
日志是維護文件系統元數據一致性的常用技術,它將不同的文件系統元數據更新集合(如目錄操作)作為原子事務提交,并且傳統上按順序提交元數據更新。
然而,開發人員不應認為這是一種保證。日志是一種內部文件系統技術,在保持內部一致性的同時也會逐漸重新排序更多的操作。例如,ext3重新排序只覆蓋文件數據,而 ext4還重新對排序文件進行追加。同時運行多個應用程序時,文件系統需要重新排序以獲得良好的性能。
開發人員的應對
開發人員可以通過以下方法法來緩解應用崩潰后的數據一致性問題:
使用一個庫
只要有可能,一個明智的策略是使用一個庫,比如 SQLite,在應用程序的底層實現崩潰后的數據一致性。
文檔承諾
應用程序提供的崩潰后數據一致性承諾可能令人困惑, 一些開發人員可能不清楚應用程序可以提供的承諾,因為通常都不清楚文件系統的那些行為。最好的文檔承諾是提供所支持的文件系統配置列表。
測試
由于文件系統表現出令人困惑的崩潰行為,因此測試非常重要。尤其是一些用于測試文件系統的工具,可以用于任何運行在 Linux 上的應用程序,盡管效率較低。
未來的可能
能否幫助開發人員構建正確的數據更新協議呢?如果可以驗證給定應用程序測試用例的各種模擬系統崩潰的正確性就好了。
文件系統本身能否提供更好的抽象呢?擴展和改進當前的文件系統接口(在 Unix 或 Windows 中)是不容易的。解決方案可能是使用當前的文件系統接口提供更好的崩潰行為。然而,按順序更新在多任務環境中并不適用。如果不在這些環境中重新排序,應用程序的性能將在很大程度上取決于其他應用程序在后臺編寫的數據,因此是不可預測的。
能否對文件系統進行建模呢?用一個抽象的持久性模型來完全表達文件系統的崩潰行為是否可行呢?
除了文件系統之外,應用程序崩潰后的數據一致性是一個有趣的問題,整個存儲堆棧都面對著這個問題.......