我們這一課討論主從復(fù)制(Primary/Backup Replication)
這一課討論關(guān)于容錯(cuò)(Fault-Tolerance)和復(fù)制(Replication)的問題,主要研究 VMware FT 的論文 —— The Design of a Practical System for Fault-Tolerant Virtual Machines
復(fù)制的方式
在集群中實(shí)現(xiàn)復(fù)制主要通過兩種方式:
- 狀態(tài)轉(zhuǎn)移(State Transfer):主機(jī)(Primary)將自己所有的狀態(tài),拷貝并發(fā)送給備機(jī)(Backup),一般是增量備份;
- 復(fù)制狀態(tài)機(jī)(Replicated State Machine):將備機(jī)視為一個(gè)確定的狀態(tài)機(jī)——client 發(fā)送操作到主機(jī),主機(jī)按順序發(fā)送到備機(jī),所有備機(jī)執(zhí)行所有的操作,如果從同一起始狀態(tài),以相同的順序輸入相同的操作,它們的輸出將是相同的。
VMware FT 使用了復(fù)制狀態(tài)機(jī)的方法。
狀態(tài)轉(zhuǎn)移傳輸?shù)目赡苁莾?nèi)存,而復(fù)制狀態(tài)機(jī)傳輸來自客戶端的操作或者其他外部事件,人們傾向于使用復(fù)制狀態(tài)機(jī)的原因是,外部操作或事件通常比服務(wù)的內(nèi)存狀態(tài)要小。例如,如果是一個(gè)數(shù)據(jù)庫(kù),它的內(nèi)存狀態(tài)可能達(dá)到 GB 級(jí)別。
復(fù)制的挑戰(zhàn)
要考慮的幾個(gè) Big Question:
- 我們要復(fù)制哪些狀態(tài)?
- 主機(jī)必須等待備機(jī)備份完嗎?
- 什么時(shí)候切換到備機(jī)?
- 切換時(shí)能否看到異常情況?
- 如果有個(gè)副本故障了,我們需要重新添加一個(gè)新的副本,這可能是一個(gè)代價(jià)很高的行為,因?yàn)楦北究赡芊浅4螅绾翁嵘砑有赂北镜乃俣?
讓我們看看虛擬化巨頭 VMware 是怎么做的。
VMware FT 論文總結(jié)
總覽
如圖 1,約定:主虛擬機(jī)(Primary VM)簡(jiǎn)稱為主機(jī),Backup VM 簡(jiǎn)稱為備機(jī)。
VMware FT 需要兩臺(tái)物理服務(wù)器,主機(jī)與備機(jī)保持同步,虛擬機(jī)的虛擬磁盤在共享存儲(chǔ)上。
所有的輸入(如網(wǎng)絡(luò)、鼠標(biāo)、鍵盤等)都會(huì)輸入到主機(jī),然后通過 Logging channel 轉(zhuǎn)發(fā)到備機(jī),對(duì)于非確定性的操作,還將發(fā)送額外的信息,確保備機(jī)以確定性的方式執(zhí)行這些操作。
兩臺(tái)虛擬機(jī)都會(huì)執(zhí)行輸入操作,但只有主機(jī)的輸出會(huì)返回客戶端,備機(jī)的輸出會(huì)被管理程序丟棄。
確定性重放(Deterministic replay)
不確定性(Non-Deterministic)事件比如虛擬中斷,不確定性操作比如從處理器讀取時(shí)鐘周期計(jì)數(shù)器,可能會(huì)讓主機(jī)和備機(jī)的運(yùn)行結(jié)果不一樣。
這帶來三個(gè)挑戰(zhàn):
- 正確捕獲所有輸入和必要的不確定性輸入來保證備機(jī)確定性執(zhí)行;
- 正確在備機(jī)執(zhí)行不確定性輸入;
- 不降低系統(tǒng)的性能;
VMware 確定性重放(deterministic replay)能夠捕獲所有輸入和可能的不確定性輸入,并寫到日志文件記錄下來。通過讀取日志文件,可以準(zhǔn)確重放虛擬機(jī)的執(zhí)行。
對(duì)于不確定性輸入,必須記錄足夠的信息來重放,但是論文中沒有描述具體的日志格式,Robert 教授猜測(cè)可能有三種記錄:
事件發(fā)生時(shí)的指令序號(hào);
日志類型??赡苁瞧胀ǖ木W(wǎng)絡(luò)數(shù)據(jù)輸入,也可能是怪異的指令;
數(shù)據(jù)。
FT 協(xié)議(FT Protocol)
VMware FT 通過確定性重放來產(chǎn)生相關(guān)的日志條目,但不將日志寫入磁盤,而是通過 logging channel 發(fā)送給備機(jī)。備機(jī)實(shí)時(shí)重放日志項(xiàng)。
為了容錯(cuò),必須在 loggin channel 上實(shí)現(xiàn)嚴(yán)格的容錯(cuò)協(xié)議,有以下要求:
輸出要求:如果備機(jī)在主機(jī)故障后接管,備機(jī)將以和主機(jī)已經(jīng)向外界發(fā)送的輸出完全一致的方式繼續(xù)運(yùn)行。
最簡(jiǎn)單的方式是對(duì)每一個(gè)輸出操作創(chuàng)建一個(gè)特殊的日志項(xiàng)。
但有一種情況,假設(shè)虛擬機(jī)運(yùn)行的是數(shù)據(jù)庫(kù),主機(jī)備機(jī)的數(shù)據(jù)都是 10。現(xiàn)在客戶端發(fā)送自增請(qǐng)求,主機(jī)做了 +1 并回復(fù)給客戶端 11,之后馬上宕機(jī)了,更糟糕的是主機(jī)發(fā)送給備機(jī)的 +1 操作也丟包了。這時(shí)候備機(jī)還是 10,并接管了主機(jī)的工作,客戶端再次請(qǐng)求 +1,又會(huì)收到 11 的回復(fù)。客戶端會(huì)得到一個(gè)怪異的結(jié)果(自增兩次還是 11)。
所以要求:
輸出規(guī)則:主機(jī)直到備機(jī)接收并確認(rèn)了和輸出相關(guān)的日志的時(shí)候,才發(fā)送輸出給外界。
這樣做的目的是,只要備機(jī)收到了所有的日志條目,即使主機(jī)宕機(jī)了,備機(jī)仍能夠重放到客戶端最后看到的狀態(tài)。
如圖 2 所示,向外界的輸出會(huì)被延遲,直到主機(jī)收到來自備機(jī)的確認(rèn)。
幾乎每一個(gè)復(fù)制系統(tǒng)都有這個(gè)問題:在某個(gè)時(shí)間點(diǎn),主機(jī)必須停下來等待備機(jī),這肯定會(huì)限制性能。
注意:因?yàn)闆]有兩階段提交事務(wù),不能保證所有的輸出只被生成一次。備機(jī)無法判斷主機(jī)是在宕機(jī)之前還是之后發(fā)送了最后的輸出,備機(jī)可能會(huì)重新執(zhí)行一次輸出操作。不過,VMware 通過其網(wǎng)絡(luò)基礎(chǔ)設(shè)施來檢測(cè)重復(fù)數(shù)據(jù)包,并防止輸出重傳到客戶端。
發(fā)現(xiàn)與處理故障
主機(jī)和備機(jī)必須快速知道另一方故障,通過 udp 心跳包和監(jiān)控 logging channel 上的流量相結(jié)合來檢測(cè),如果心跳超時(shí)或 logging channel 流量停止則表明故障。
如果備機(jī)故障,主機(jī)就會(huì)停止向 logging channel 發(fā)送日志,繼續(xù)正常運(yùn)行。
在這之后備機(jī)怎么追上主機(jī)呢?VMware有一個(gè)工具叫 VMotion,它能夠在最小程度上中斷虛擬機(jī)的執(zhí)行,克隆一個(gè)虛擬機(jī)。
如果主機(jī)故障,備機(jī)必須先重放,直到消耗完最后一個(gè)日志項(xiàng)。然后備機(jī)接替主機(jī),開始向客戶端生產(chǎn)輸出。
為了確保一次只有一個(gè)虛擬機(jī)成為主機(jī),避免出現(xiàn)腦裂,VMware 在共享存儲(chǔ)上執(zhí)行一個(gè)原子的 test-and-set 鎖指令。該操作每次只能對(duì)其中一臺(tái)機(jī)器返回成功,這在主機(jī)和備機(jī)因?yàn)榫W(wǎng)絡(luò)分區(qū)都想接替工作時(shí)很有用。但如果共享存儲(chǔ)因?yàn)榫W(wǎng)絡(luò)問題不能訪問,那么無論如何都不能正常工作。
當(dāng)其中一臺(tái)虛擬機(jī)發(fā)生故障時(shí),VMware FT 會(huì)在另一臺(tái)物理機(jī)上自動(dòng)啟動(dòng)新的備份虛擬機(jī)來恢復(fù)冗余。
FT 的實(shí)際實(shí)現(xiàn)細(xì)節(jié)
上一節(jié)描述了容錯(cuò)的基礎(chǔ)設(shè)計(jì)和協(xié)議,但為了創(chuàng)建一個(gè)可用的、健壯的自動(dòng)化系統(tǒng),還需要設(shè)計(jì)和實(shí)現(xiàn)許多其他組件。
啟動(dòng)和重啟 FT VMs
一個(gè)挑戰(zhàn)是,如何在主機(jī)運(yùn)行時(shí),以和主機(jī)相同的狀態(tài)啟動(dòng)備機(jī)?為了解決這個(gè)問題,VMware 提供一個(gè)名為 VMware VMotion 的工具,允許在最小化中斷的代價(jià)下,將運(yùn)行中的虛擬機(jī)從一臺(tái)服務(wù)器遷移到另一臺(tái)服務(wù)器。為了容錯(cuò),該工具被重新設(shè)計(jì)為 FT VMotion,以允許將虛擬機(jī)克隆到遠(yuǎn)程主機(jī)上,這種克隆操作打斷主機(jī)的時(shí)間不超過 1 秒。
管理 Logging Channel
上圖 3 說明了日志從主機(jī)產(chǎn)生到在備機(jī)上消費(fèi)的過程。
虛擬機(jī)管理程序維護(hù)了一個(gè)大的日志緩沖(log buffer),保存主機(jī)和備機(jī)的日志。主機(jī)會(huì)產(chǎn)生日志項(xiàng)到日志緩沖,備機(jī)從日志緩沖消費(fèi)日志。
如果備機(jī)讀到空的日志緩沖,則會(huì)暫停運(yùn)行直到日志緩沖有日志;如果主機(jī)寫日志的時(shí)候發(fā)現(xiàn)日志緩沖滿了,也會(huì)暫停運(yùn)行直到日志項(xiàng)被清除——這種暫停會(huì)影響虛擬機(jī)的客戶端。因此,我們的實(shí)現(xiàn)必須最小化主機(jī)日志緩沖寫滿的可能性。
通常,主機(jī)日志緩沖滿的原因:
- 帶寬太小,建議日志通道帶寬 1Gbit/s;
- 備機(jī)執(zhí)行速度太慢,從而消費(fèi)日志太慢時(shí),主機(jī)的日志緩沖也可能會(huì)被填滿;
在 VMware FT 中已經(jīng)實(shí)現(xiàn)了一種機(jī)制,當(dāng)備機(jī)遠(yuǎn)遠(yuǎn)落后時(shí)(根據(jù)論文中的說法,落后超過1秒),可以減緩主機(jī)的執(zhí)行速度。通過減少主機(jī)的 CPU 資源來減慢速度。
注意對(duì)于主機(jī)的減速是很罕見的,通常只在系統(tǒng)處于極端壓力的情況下發(fā)生。
磁盤 IO 實(shí)現(xiàn)問題
有一些和磁盤 IO 相關(guān)的細(xì)微的實(shí)現(xiàn)問題。
問題 1:非阻塞的磁盤操作可以并行執(zhí)行,因此對(duì)同一磁盤位置的同時(shí)訪問可能導(dǎo)致不確定性。
解決方案:檢測(cè)所有這類 IO 競(jìng)爭(zhēng),然后強(qiáng)制這些競(jìng)爭(zhēng)的磁盤操作以相同的方式在主機(jī)和備機(jī)上順序執(zhí)行。
怎么檢測(cè)?論文也沒說。
問題 2:虛擬機(jī)上的應(yīng)用程序(或操作系統(tǒng))的磁盤操作也可能導(dǎo)致內(nèi)存的競(jìng)爭(zhēng)
解決方案:通過 Bounce buffer—— 一個(gè)和磁盤操作正在訪問的內(nèi)存大小一致的臨時(shí)緩沖來解決。磁盤讀操作被修改為在 bounce buffer 中讀取特定數(shù)據(jù),并且數(shù)據(jù)僅在IO操作完成并傳遞完成的時(shí)候拷貝到虛擬機(jī)內(nèi)存。類似的,對(duì)于磁盤寫操作,將要被發(fā)送的數(shù)據(jù)會(huì)先拷貝到 bounce buffer,磁盤寫操作修改為寫數(shù)據(jù)到 bounce buffer。
Bounce buffer 的使用會(huì)減慢磁盤操作,但是論文表示還沒有看到任何明顯的性能差異。
問題3:磁盤 IO 因主機(jī)故障在主機(jī)上沒有完成,備份接管后怎么辦?
解決方案:發(fā)送錯(cuò)誤來表明 IO 失敗,然后重試錯(cuò)誤的 IO。
替代方案
本節(jié)討論一些替代方案,以及他們所做的權(quán)衡。
共享磁盤與非共享磁盤:VMware FT 使用了一個(gè)主備機(jī)都能訪問的共享存儲(chǔ)。一個(gè)替代方案是使用單獨(dú)(非共享)的虛擬磁盤,主備機(jī)分別寫入這些磁盤。這種設(shè)計(jì)可以用在共享存儲(chǔ)不能同時(shí)被主、備機(jī)訪問,或者共享存儲(chǔ)太貴的情況下。缺點(diǎn)是需要做額外的工作,必須同步磁盤狀態(tài)。
在備機(jī)上執(zhí)行磁盤讀取:在目前實(shí)現(xiàn)中,備機(jī)絕不會(huì)從磁盤進(jìn)行讀取,磁盤操作被認(rèn)為是一種輸入。一個(gè)替代的設(shè)計(jì)是,備機(jī)可以執(zhí)行磁盤讀取,當(dāng)有大量磁盤讀的工作負(fù)載時(shí),這種方法可以幫助減少日志通道的流量。然而,這種方法有兩個(gè)主要挑戰(zhàn):
可能會(huì)減慢備機(jī)的執(zhí)行速度,因?yàn)閭錂C(jī)必須執(zhí)行所有的磁盤讀;
如果讀取在主機(jī)上成功,但在備機(jī)上失敗(反之亦然)怎么辦?必須做一些額外的工作來處理失敗的磁盤讀操作。
VMware 的性能評(píng)估顯示,在備機(jī)上執(zhí)行磁盤讀取會(huì)降低 1-4% 的吞吐量,但同時(shí)也降低了日志帶寬。
FAQ
來自:https://pdos.csail.mit.edu/6.824/papers/vm-ft-faq.txt
Q: GFS 和 VMware FT 都提供了容錯(cuò)性,哪一個(gè)更好?
FT 提供計(jì)算容錯(cuò),你能用它為任何已有的網(wǎng)絡(luò)服務(wù)器提供容錯(cuò)性。FT 提供了相當(dāng)嚴(yán)格的一致性而且對(duì)客戶端和服務(wù)器都是透明的。例如,你可以將 FT 應(yīng)用于一個(gè)已有的郵件服務(wù)器并為其提供容錯(cuò)性。
GFS 只提供存儲(chǔ)容錯(cuò),因?yàn)?GFS 只針對(duì)特定的簡(jiǎn)單服務(wù)(存儲(chǔ))提供容錯(cuò)性,它的備份策略會(huì)比 FT 更高效。例如,GFS 不需要使中斷都以完全相同的指令發(fā)生在所有的副本上。GFS 通常只會(huì)用于一個(gè)對(duì)外提供完整容錯(cuò)服務(wù)的系統(tǒng)的一部分。例如,VMware FT 本身也依賴了一個(gè)在主備機(jī)間共享的有容錯(cuò)性的存儲(chǔ)服務(wù),而你則可以用類似于 GFS 的東西來實(shí)現(xiàn)這個(gè)共享存儲(chǔ)(雖然從細(xì)節(jié)上來講 GFS 不太適用于 FT)。
Q: 共享存儲(chǔ)上的原子 test-and-set 指令是什么?
在共享存儲(chǔ)上的一個(gè)服務(wù),最初狀態(tài)為 false,主機(jī)或備機(jī)認(rèn)為對(duì)方宕機(jī)了,自己應(yīng)該接管的時(shí)候,首先要向共享存儲(chǔ)發(fā)送一個(gè) test-and-set 操作,偽代碼是:
- test-and-set() {
- acquire_lock()
- if flag == true:
- release_lock()
- return false
- else:
- flag = true
- release_lock()
- return true
只有當(dāng)返回 true 時(shí)才能接管主機(jī)。主要為了避免當(dāng)主、備機(jī)出現(xiàn)網(wǎng)絡(luò)分區(qū),都想接管時(shí)出現(xiàn)腦裂(即同時(shí)有兩個(gè)主機(jī))的情況。
這有點(diǎn)像一個(gè)分布式鎖。問題是:偽代碼沒有展示什么時(shí)候 flag會(huì)被設(shè)為 false!
老師解釋:論文沒有提及什么時(shí)候?qū)?flag 重設(shè)為 false,也許是管理員人為的操作,也許是交給機(jī)器來清理。
小結(jié)
本節(jié)討論了主從復(fù)制這個(gè)經(jīng)典的分布式話題,主備模式幾乎是數(shù)據(jù)庫(kù)系統(tǒng)最常見的高可用方案,這篇論文擴(kuò)充了我的主從復(fù)制的了解。
但論文也提到這個(gè)系統(tǒng)的一個(gè)局限性:僅支持單處理器,多核并行所涉及的不確定性將使系統(tǒng)的實(shí)現(xiàn)更具挑戰(zhàn)性。現(xiàn)實(shí)中的 VMware 是支持多核,但 VMware FT 的論文完全沒有討論,這需要去查閱更多的資料。
Reference
The Design of a Practical System for Fault-Tolerant Virtual Machines: https://pdos.csail.mit.edu/6.824/papers/vm-ft.pdf
Lecture 4: Primary/Backup Replication: https://pdos.csail.mit.edu/6.824/notes/l-vm-ft.txt
VMware FT FAQ: https://pdos.csail.mit.edu/6.824/papers/vm-ft-faq.txt
VMotion: https://www.vmware.com/pdf/vmotion_datasheet.pdf
Deterministic replay: http://www-mount.ece.umn.edu/~jjyi/MoBS/2007/program/01C-Xu.pdf
本文轉(zhuǎn)載自微信公眾號(hào)「多顆糖」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系多顆糖公眾號(hào)。