硬碟寫到一半斷電時文件系統發生了什麼?
斷電時文件系統發生了什麼?硬碟又發生了什麼?下一次開機時寫到一半的文件在系統層面還在嗎?在底層還在嗎?
更進一步的, 文件系統如何保證事務性, 會不會存在某種極端情況導致例如最後幾個bit還沒寫完, 文件系統卻認為它成功了的情況?
回答不限任何文件系統,謝謝!
這事說起來挺複雜的,不同文件系統,不同設備,不同介質,效果都是有區別的。
斷電的一瞬間,很多事情是無法確定的:
1. 你無法確定你試圖向設備驅動發送的寫指令是否成功,驅動程序本身一般都有緩存;
2. 即使寫指令正常返回,你也無法確定設備實際上是否寫成功,因為設備本身可能也有緩存。目前沒有設備能保證寫指令返回的情況下,所有數據一定成功的保存在介質上(但部分廠商能保證少量數據一定能成功寫入),對存儲設備的flush操作並非絕對可靠;
3. 哪些成功哪些失敗可能是亂序的,換句話說,如果先發送寫請求A,再發送寫請求B,並且都成功返回,掉電時請求A可能丟失,但B成功(NCQ功能);
4. 機械式磁碟可能會出現丟失半截數據的情況(比如,一個512位元組扇區只寫入了100位元組,也就是題主說的bit級錯誤),但這種一般都會通過校驗位檢測出來。
因為有以上這麼多的限制,實際上文件系統一般沒辦法保證數據一定不丟失,甚至哪些丟失哪些能恢復也是不確定的。
一般來說,文件系統有以下的幾種策略:
1. 完全不管錯誤的事情,錯了就錯了;
2. 打標記位的方式,如果懷疑有錯,通過磁碟檢測功能恢復;
3. 在設計上保證文件系統結構上可恢復,但不保證用戶數據可恢復;
4. 能在用戶數據層面上保證數據的絕對正確。
第一種和第二種策略現在比較少見,FAT文件系統算是屬於這類;主流文件系統基本上都能保證第三種,比如NTFS之類的;第四種比較難,一般都要配合存儲驅動一起,多見於Flash介質的專屬文件系統。
保證數據不損壞,具體的方案一般有:
方案1:Copy-On-Write,寫數據的時候不在原來的位置寫,而是先讀一份,然後寫到另外一個位置,當確認寫成功時,把文件系統的指針指向新的位置。如下圖:
實際應用中,比這個情況複雜,因為Data2寫入的過程中,File1本身的一些信息(修改時間等)也發生了變化,所以CopyOnWrite產生的影響不止這一個塊,而是很多。
方案2:日誌(Journal)技術。使用日誌記錄meta-data甚至是數據塊的變化情況(NTFS就是這種策略),一旦出現掉電情況,在日誌中反推到一個正確的狀態上,就可以保證meta-data不損壞。
常見的方案就這兩種,當然還有別的更複雜的技術,可以參考這個鏈接(Comparison of file systems),但不管用什麼方案,本質上都是以犧牲性能為代價換取結構上的穩定。
最後回到題主的問題,文件系統如何保證數據的正確性?如果是指文件的數據部分,是無法保證的,因為文件系統無法確定數據到底寫沒寫進去,絕大多數文件系統只能保證自身結構是正確的,但這個正確可能是回滾之後的狀態,具體回滾多少內容,文件系統自己也不能保證。
文件系統的設計一般是性能和數據完整性的妥協,如果你想要最高完整性,那麼性能會差一些,如果你想要最高性能,那麼數據完整性會差一些,僅此而已。當然這些都是針對數據而言的,對於文件系統自身的元數據,一般設計者為了自身數據完整性的考慮都會有日誌系統(比如ext4使用jbd2),從而盡量保證文件系統在斷電時沒有問題或者問題很少(需要使用fsck來解決),但是用戶數據是否完備是由用戶選擇和配置的,而文件系統會根據不同配置選擇不同的策略。
我們以Linux最通用的ext4為例,他有三種模式供用戶選擇data=writeback/ordered/journal,對應的是數據落盤的三種方式,writeback是指元數據更新的時候數據不考慮是否落盤,所以掉電以後可能會看到一些亂七八糟的數據,ordered的意思是元數據更新在數據更新之後(如果你沒有更改元數據那就沒有辦法保證數據了),還有一種是journal意思是數據也先寫journal再寫文件(double write),這種數據安全性最高,當然性能也最差。詳細的介紹可以參加mount(8)。
說完文件系統,我們再說硬碟,硬碟在文件系統下面,所以文件系統是重度依賴硬碟來實現數據完整性的,而硬碟也提供了一些命令來保障文件系統數據完整性的語義。比如硬碟會提供flush命令,保證只要上層文件系統調用了這個命令,那麼文件系統之前寫到硬碟裡面的內容必須落盤了(一般的硬碟有內存cache,為了提高寫入性能會緩存一部分數據,flush會命令硬碟將cache內容落盤。當然如果硬碟如果有電容可以保證cache即使掉電也會落盤,那麼他也可以欺騙上層的文件系統 ),這樣文件系統在寫入一些關鍵數據以後必須調用flush,在得到硬碟的flush反饋以後再進行後面的工作。當然現代硬碟還有一些FUA(Force Unit Access)之類的操作,這些是為了加速某類磁碟落盤的操作,本質上即使硬碟不提供文件系統可以改成write+flush來實現(只是性能差一些),如果感興趣大家可以自行google之。
說完底層,還有一層要說一下,就是你的應用是怎麼寫文件和硬碟的,如果是buffer write(應用只寫到操作系統的內存,由操作系統延遲回寫到硬碟),那麼很大可能你在掉電之前一段時間寫入的數據都會不見了(操作系統還沒有回寫),如果應用是direct IO(應用繞過操作系統內存,直接寫硬碟),那麼可能只有掉電時刻正在寫入的數據不見了,當然這裡可能還涉及到direct IO的語義以及不同文件系統的具體實現,和文件系統相關,就需要具體問題具體分析了。
這個問題應該有不少做法:比如,通常文件是有結構的,每個結構都可以自校驗的,進程突然被殺/系統突然掉電等異常情況發生後,再次啟動時,系統正常關閉的標識是沒有的,這時就會做數據完整性檢查,從而發現和剔除有問題的記錄。
這種事情就像你改一個數據結構改了一半,突然把那個線程殺掉了一樣。如果你設計的好(譬如說Transactional NTFS),你就可以在最終commit之前讓數據結構被訪問的時候不會感知到變化。
舉個簡單的例子,雖然我猜應該不會有人這麼做的。你在文件後面新添加一段數據,其實一個文件就是一個鏈表,因此你有兩種選擇:
1、開闢空間 -&> 鏈接上去 -&> /*斷電*/ -&> 往最後一個節點寫數據2、開闢空間 -&> 往最後一個節點寫數據 -&> /*斷電*/ -&> 鏈接上去選1的話,斷電了你就會看到垃圾數據。選2的話,斷電了你就會發現這個文件沒有變。你無法確定你試圖向設備驅動發送的寫指令是否成功,驅動程序本身一般都有緩存;
硬碟上的數據是不完整的,但是成熟的文件系統可以保證文件是完整的。比如修改了一個文件,保存的時候掉電了,那麼下次上電,這個文件要不是修改前(寫了一半的數據可能會被當垃圾數據處理),要不在修改後。
你沒拔強過電腦電源嗎?
結果就是頂多要做個文件系統修復,為啥呢?因為現在的文件系統大部分是日誌文件系統。如果你知道oracle的歸檔日誌可以回滾的話,你就能理解了這不蘋果的APFS上熱搜了了,來答個題,手癢。
這個問題是要問文件系統到底要保護什麼東西!文件系統中的數據包括:元數據與用戶數據。其中元數據是文件系統要掉電保護的,用戶數據是用戶自己控制是否需要保護。
元數據我們在用戶態看不到,比如inode、實際的目錄數據結構、針對特定文件系統的特定元數據等。這些數據在用戶態看不到,是整個文件系統的根基,它是水面下的基座,撐起了一整座冰山。元數據屬於文件系統的元數據,一定要保證一致性!
用戶數據是你存儲的一個word,excel,txt,視頻,音樂等文件,文件系統提供了fdatasync/fsync介面供用戶使用,當這些系統調用成功返回,那麼即便異常掉電,數據也必須能恢復。用戶數據是屬於用戶的,具體內容文件系統不感知。
作個比喻:小件寄存室就是文件系統,裡面總共有多少個格子,還剩多少個格子都是要記錄好保證一致的【不能告訴別人還有地兒,人家存進來之後發現沒格子用】。用戶數據就是小件咯,有時你是看著小件放進了格子、上鎖後再走,這就是保證你的數據落盤,這種你下次來一定還能找到;但是有時你把小件放在了暫存台讓店主幫忙放,那麼你下次來小件很可能就丟了,因為來場大風把小件給刮跑咯。
一般現在大多都是日誌文件系統,比如win的NTFS,或者Linux的ext4或者更新一些的fs。日誌意思就是說我在進行操作的時候,除首先將用戶的數據寫入到磁碟上,然後還會在fs里記錄一條日誌,這樣如果發生掉電,上電後以日誌為準,就可以保障數據不亂,最多就是剛才寫的數據丟掉了。
至於說硬碟會怎樣,沒研究過,不好說,機械盤的話,磁頭和磁碟之間是貌似是考旋轉的氣動力保持間距的,所以如果突然掉電也許會劃傷磁碟,但也可能在轉數降下來之前,主控來得及把磁頭移動到安全區域。好吧,知乎上真是卧虎藏龍,這個問題我就看到了國家科技進步一等獎獲得者,和國際頂級內核開發者的蹤影。菊花一緊,拜一下。
會損壞,但是也可以恢復
不過恢復成本嘛。。。
要是軍事機密什麼的,恢復幾年,耗資幾個億也要弄回來
這破事,你們又不給錢,幹嘛費勁吧列的恢復啊?
垃圾知乎,直接從單純從技術的角度分析,多次強制斷電會使存儲硬碟損壞嗎? 彈到這裡了
文件系統保證事務性的機制與資料庫類似,都是寫日誌。不過文件系統的事務和日誌相對而言要簡單一點點。而且文件系統一般僅保證元數據點事務性,不管用戶數據。否則,性能實在太差了。
一般地,
文件系統是不會管你文件寫完沒寫完的(現在的文件系統一般可以保證自身不受損壞,然而讀寫的文件並不能保證是完好的)。處理文件完整性的一般是程序自身。
像iOS系統中的Swift語句
xxx.write(toFile: path, atomically: false)
這裡的"atomically"參數就是處理意外斷電(錯誤)時用的,atomically 為true時,寫入臨時文件,待寫完後無錯誤,才寫入到文件中。如果其為false,那麼數據就會直接寫入到程序中,此時如果突然斷電(或者閃退),文件就會損壞,並有很大幾率會無法被讀取。
以上
推薦閱讀:
※個人開發web應用,從需求設計,界面設計,資料庫設計,API設計等,好的開發流程是怎麼樣的?
※目前流行病學有成熟的資料庫嗎?
※資料庫學習有哪些好的推薦教材?
※什麼是資料庫的一致性?一致性弱意味著什麼?NoSQL 的弱一致性又為什麼是可以被接受的?
※OnlineJudge系統的判題數據,用資料庫存、用文件存哪種比較好?