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