容錯虛擬機分布式系統(tǒng)的設(shè)計
這篇文章是我閱讀論文《 The Design of a Practical System for Fault-Tolerant Virtual Machines 》時的筆記,這篇論文是 VMware 發(fā)表的論文,使用虛擬機來設(shè)計一個分布式容錯系統(tǒng)。
在分布式系統(tǒng)中,容錯方法有很多種,常見的傳統(tǒng)方法有:主/副服務(wù)器方法(當主服務(wù)器宕機之后,由副服務(wù)器來接管它的工作),這種方法通常需要機器之間的高帶寬。
另外還有確定(deterministic)狀態(tài)機方法:將另一臺服務(wù)器初始化為和主服務(wù)器一樣的狀態(tài),然后讓它們都接受到同樣的輸入,這樣它們的狀態(tài)始終保持一致,但是這種方法對于非確定的(non-deterministic)操作并不適用。
本文中討論的方法是使用虛擬機作為狀態(tài)機,它具有以下優(yōu)點:
- 操作全部被虛擬化
- 虛擬機本身就支持 non-deterministic 操作
- 虛擬機管理程序(Hypervision)能夠記錄所有在虛擬機上的操作,所以能夠記錄主服務(wù)器(Primary)所有操作,然后在副服務(wù)器(Backup)上進行演繹
基本設(shè)計方案
如圖就是本文提到的容錯系統(tǒng)的架構(gòu),一個 Primary,一個 Backup,Primary 和 Backup 之間通過 Logging Channel 進行通信,Primary 和 Backup 基本保持同步,Backup 稍稍落后,它們兩個之間會通過 heartbeat 進行 fail 檢測,并且它們使用共享磁盤(Shared Disk)。
確定(deterministic)操作的演繹
讓兩臺機器初始狀態(tài)相同,它們接受相同的輸入,順序相同,兩臺機器執(zhí)行的任務(wù)的結(jié)果就會相同。
但是如果存在非確定的(non-deterministic)操作(比如中斷事件、讀取CPU時鐘計數(shù)器的值操作就是非確定的),它會影響狀態(tài)機的執(zhí)行。
難點在于:
- 需要捕捉全部的輸入和 non-deterministic 操作在保證 Backup 是deterministic 的
- 需要準確將全部輸入和 non-deterministic 操作應(yīng)用到 Backup 中
- 需要保證系統(tǒng)高效
設(shè)計方案為:將所有的 input 和 non-deterministic 操作寫入到 log 中(file),對于 non-deterministic 操作還要記錄和它相關(guān)的狀態(tài)信息等,確保 non-deterministic 操作后Backup狀態(tài)還是和 Primary 一致
FT(Fault-Tolerance)協(xié)議
FT 協(xié)議是應(yīng)用于 logging channel 的協(xié)議,協(xié)議的基本要求為:
如果 Primary 宕機了,Backup 接替它的工作,Backup 之后向外界發(fā)出所有的 Output 要和 Primary 原本應(yīng)當發(fā)送的一致。
為了保證以上的要求,設(shè)計如下系統(tǒng):
- Primary會在所有關(guān)于本次Output 的所有信息都發(fā)送給 Backup 之后(并且要確保 Backup 收到)才會把 output 發(fā)送給外界
- Primary 只是推遲將 output 發(fā)送給外界,而不會暫停執(zhí)行后邊的任務(wù)
流程如圖所示:
但是這種方法不能保證 output 只發(fā)出一次,如果 primary 宕機了,backup 不能判斷它是在發(fā)送了 output 之前還是之后宕機的,因此 backup 會再發(fā)送一次 output。但是這個問題很容易解決,因為:
- output 是通過網(wǎng)絡(luò)進行發(fā)送的,例如 TCP 之類的網(wǎng)絡(luò)協(xié)議能夠檢測重復(fù)的數(shù)據(jù)包
- 即使 output 被發(fā)送了2次其實也沒關(guān)系。如果 output 是一個寫操作,它會在同一個位置寫入兩次,結(jié)果不會發(fā)生變化;如果 output 是讀取操作,讀的內(nèi)容會被放入 bounce buffer(為了消除 DMA 競爭),數(shù)據(jù)會在 IO 中斷之后被送到
宕機檢測
如何知道有機器宕機,在該系統(tǒng)中是十分重要的。該設(shè)計使用的是UDP heartbeat 機制來檢測 Primary 與 Backup 之間的通信是否正常。
但是使用這種方法會存在裂腦問題(split-brain,Primary 和 Backup 同時宕機),該怎么解決呢?
該設(shè)計中使用了共享存儲(Shared Storage),對它的操作是原子的,Primary 和 Backup不能同時進行一個操作(提供原子的 test-and-set 操作)
如果檢測出 Primary 宕機,Backup 會成為 Primary,接替之前的工作,然后再尋找一個 Backup。
具體實現(xiàn)
啟動/重啟 Virtual Machine
如何啟動一個和 Primary 狀態(tài)一樣的 Backup?
VMware Vmotion 操作能夠?qū)⒁慌_ VM 從一個 Server 完整的遷移到另一個 Server(只需要很短的中斷),在該設(shè)計中的方法對 Vmotion 做了一點修改,不是進行遷移,而是直接克隆。
管理 Logging Channel
如圖,該設(shè)計使用了一個大的 buffer,來保存 logging entries,Primary 把自己的 entry 存到 buffer 中,由 logging channel 發(fā)送給Backup 的 buffer,然后 Backup 從 buffer 讀取命令執(zhí)行。
- 如果 Backup 的 buffer 空了,沒有命令執(zhí)行了,Backup 會等待新的 entry
- 如果 Primary 的 buffer 滿了,Primary 會等待,等 buffer 中有空余空間再繼續(xù)執(zhí)行
Disk I/O問題
disk 操作是并行的,同時對 disk 的同一位置進行操作會導(dǎo)致 non-deterministic
解決方案:檢測 IO 競爭,使這些操作串行執(zhí)行
Disk IO 使用 DMA(Direct Memory Access),同時訪問內(nèi)存同一位置的操作會導(dǎo)致 non-deterministic
解決方案:對 disk 操作的內(nèi)存設(shè)置內(nèi)存的頁保護,但是這種方法代價太高;該設(shè)計中使用了 bounce buffer,它的大小和 disk 所操作的內(nèi)存部分大小是一致的,read 操作直接將內(nèi)容讀入 buffer,當其他操作完成,寫入內(nèi)存,write 操作將寫內(nèi)容寫入 buffer,之后再寫入磁盤。
總結(jié)
Vmware 提出的這種 Primary/Backup 方法是分布式容錯方法中非常重要的一部分,可以用在許多系統(tǒng)中,不僅僅是分布式存儲(GFS 的容錯方法),也可以用在分布式計算中,因為它是將所有的操作都記錄下來,將它們重新在 Backup 上進行演繹,從而起到了備份的作用,能夠做到容錯(Fault-Tolerance)。