聊聊這個讓騰訊云丟數據的“靜默損毀”
剛看到一則新聞,說是騰訊云丟了某個客戶的數據,原因是硬盤bug導致“寫進去的數據讀出來并不是之前寫入的數據”,當然,不管具體是不是這個原因,詳情如何,不做評論。本次冬瓜哥就來聊聊這個數據靜默損毀(silent corruption)的一系列底層知識。
本文就是對靜默損毀做簡要總結性介紹。靜默損毀大概有幾種方式:
parity error 每個扇區都會有ecc校驗區,硬盤寫入數據之前會計算ecc,并在讀出數據之后自行校驗。按理說這樣應該不會靜默損毀?不是的。如果host端發給硬盤的數據已經是錯的了,那么硬盤就不會知道。所以,人們使用DIF(Data Integrity Field)來實現上層的校驗,也就是說,硬盤上位角色(比如HBA,或者應用)主動校驗數據并將校驗碼寫入另外的8字節中,隨著512字節的扇區數據一起下發給硬盤。
DIF中可以完全自定義,也可以按照T10標準,DIF中放置扇區號、校驗碼和應用自定義信息。為何要放扇區號?這個下面再說。但是即便是有DIF,也無法保證從應用生成數據,到數據寫入硬盤一整條路徑上都不出錯,有些廠商也在致力于從數據一生成的時候就時刻跟著校驗,這個可以在應用層來透明的做。
2. paritial write。這個現象是由于硬盤在寫入數據時,只寫了一部分扇區數據,而另一部分沒有寫入。硬盤一般會保證扇區粒度的原子寫,但是由于種種不可知因素,這種partial write也會發生,最終讀出數據時多半會發現校驗出錯,從而報告。
此時上層程序可以從副本中讀出正確的數據,多個副本同時出錯的概率非常低。這個不屬于靜默損毀。在Raid系統里,一個條帶沒有完整被寫完前就掉電了,也稱為partial write,這個可以通過日志或者標記條帶完整性來解決,不是什么大問題。
3. write lose。這個現象是說硬盤本該寫入某個扇區,但是最終根本沒有寫入,目標扇區數據依然是老數據。這個現象會導致靜默損毀,導致應用讀出了舊數據,或者其它應用之前保存的完全不相關的數據,直接現象肯能是亂碼之類。
這個問題可以通過在應用層做標記的方式解決,比如應用給每個數據塊記錄一個時間戳,如果發生了lose,則時間戳一定對不上,于是就可以判斷出來。這些應用層標記可以記錄在DIF 8字節里的應用自定義區域。除了數據庫這種對一致性要求非常完備的系統,其他應用一般不會這么嚴格,所以一旦發生這個問題,只能事后恢復,比如從多個副本中再提起一遍數據做比對。無法做到事前預防。
4. mis-redirect write。這個現象是硬盤本應寫入A扇區,卻由于不可知原因寫錯了地方,寫到其他扇區去了。這個問題的原因可能是host端傳的扇區地址指針中某個或者某幾個bit發生了畸變(比如SRAM中的互鎖晶體管受到各種電離輻射粒子流轟擊,直接導致狀態改變)。
這種靜默損毀的后果更嚴重,不但本次I/O對應的扇區沒被更新,而且還破壞了其他扇區。這種損毀,也需要靠DIF中的應用自定義區段才能解決,但是這個代價太高昂,因為應用每讀出一個數據塊就要做DIF判斷。