這裏存在幾個問題,一是主機崩潰前的最後一個操做進行到哪了,二是網絡分隔的時候,會選出多臺主機,三是有的備機曾經發生過故障,上面的數據不是最新的,不能做爲主機。html
viewstampedreplication能夠解決上面三個問題算法
view的含義是,能夠互相聯繫的K臺機器,以及主機ID,要求K大於集羣中總機器數的一半。當有新的機器加入,或者有機器故障,或者更換主機,則變成另外一個VIEW了。數據庫
必須一個VIEW中全部的機器都成功,該操做纔算成功。VIEW中每臺機器都記錄最新一次操做的VIEWID及操做的時間戳。這樣,就能夠知道最後一個操做進行到哪了。由於K要求佔大多數,因此不會出現多個VIEW。根據每臺機器的記錄,選擇最新的一個,就能夠知道哪些機器的數據不是最新的。網絡
()Viewstamps算法併發
Viewstamps算法是Oki和Liskov於1988年發表的論文,Liskov是一位計算機世界中傑出的女性,08年圖靈獎得主、著名面向 對象五原則中「Liskov可替換原則」的提出者。咱們已無精力考證Viewstamps是不是第一個多數派表決的算法,但知道其比 Paxos(1998)整整早了10年,杯具的是,隨着06年googlechubby論文發表,Paxos迅速聞名於世,而Viewstamps依舊寂寂無聞。分佈式
在分佈式系統中通常經過複製來提升系統的可用性,而複製又引入了一致性的問題,好比咱們把數據複製到A、B、C三個節點,如何保證A、B、C看到的複製數據的順序是一致的?從深層次上來說,複製節點就是一個狀態機,咱們有必要時刻保證各狀態機狀態的一致。post
爲了保證複製數據的一致性,Viewstamps採用了Primary-backup模式(類Master-slave),規定全部數據操做,不管是查詢仍是更新都必須經過primary進行,而後傳遞到各backup(顯然primay-backup與數據庫的master-slave仍是不一樣 的,數據庫的master-slave強調的是「單寫多讀」),這樣,數據的一致性就獲得了保證,但primary會成爲單點,若是primary crash那進行一半的事務該如何處理?這正是viewstamps算法要解決的問題,因此viewstamps也常常被描述爲master的選舉算法。優化
另外補充幾個次重要概念:this
存在衆多繁雜且表述不一的概念,也是viewstamps算法的一大特點,翻來覆去就那麼幾樣東西,你們習慣便可。google
客戶端C發送數據到primary,primary傳播到backups,其圖以下(其中(a=primary,b,c,d,e)構成一個group,a是primary): 圖1
很顯然,在a與b,c,d,e通訊時,也稱爲發送event時,須要分佈式事務,即等待b,c,d,e返回。若是parimary a crash,則會選舉一個新的primary,以下圖2:
primary並非接收到event後當即同步到backup,而是在事務的prepare階段集中處理。前面也提到過,event確定是屬於某個view,event是按timestamps的順序發送,這樣全部的event就會造成一個viewstamps的順序。好比咱們每一個view的編號 即viewid都是全序的,即每次都會單調遞增,每一個event的順序也是全序,這樣每次primary接收到一個數據,均可轉變爲一個帶全序的 event,可記錄爲<v1.1>,<v1.2>,<v2.1>,<v2.2>...由於一個事務能夠提交多個數據最後一塊兒提交,而服務端的view會隨着cohort的crash而動態調整,所以客戶端在與primary通訊時都 須要指定哪一個事務與primary的哪一個view通訊,而primary回覆client生成的每一個event的viewstamps,以下圖3:
客戶端和primary都記錄這些數據,以準備後續的事務提交。當客戶端準備提交時,在primary接收到prepare命令時,會把其上的viewstamp記錄同步到backups上,由於viewstamp全序,就保證了這些事件會以相同的順序在backups上執行,從而獲得一個一致 的狀態。爲了保證這一點,單靠event狀態一致是不夠的,還必需要求backup不能跳號執行event,好比primary要求執 行<v2.3>,但backup發現<v2.2>還沒有執行,則必須等<v2.2>執行完畢後才能執 行<v2.3>。
爲何會有<v2.2>還沒有執行就有<v2.3>要求的狀況呢?有兩個緣由:一是網絡波動,信息傳輸有時差,但這在局域網中不多發生;二是backup可能會crash後甦醒,這個狀況比較常見。
Primary在向backups複製數據時並不要求全部的backups都成功,而只是要求包含本身在內的一個多數派成功便可(在viewstamps算法中,稱這樣的多數派爲sub-majority)。這點很是重要,詳細說明以下:
假如在如今時刻viewstamps系統正常運行,其全部cohort成員是confirutaion的一個多數派,記爲C;
系統在屢次viewchange後仍能保持一個多數派,記爲X
由於C、X都爲多數派,所以C、X至少存在一個公共cohort,記爲O,則cohort O知道系統在C中正常運行時的全部viewstamps,新的view能夠根據O還原出viewchange前的全部工做狀態,從而能爲是否提交事務做出 決策。若是不能保證存在多數派,則沒法保證viewstamps算法的正確性,也就是說在2N+1個節點中,最多容許N個節點失敗。
cohort失敗的狀況比較多,但假定數據能夠丟失、複製、亂序,但不能出現拜占庭問題,即不能篡改消息;另假設全部的失敗都是fail-stop,即失敗中止,不會在失敗狀態繼續服務。雖然假設感受比較多,但這些假設通常的通訊環境都能知足。
節點會有下面幾種失敗狀態:
前兩種錯誤會致使view change;後一種失敗由於採用強制多數派的機制,保證了雖然有一個少數派的網絡存在,但由於沒法造成多數派而沒法工做,就杜絕了存在兩個viewstamps group同時工做帶來的風險。
通常咱們會在cohort之間保持心跳檢測,一旦某個cohort在指定的時間沒有收到其餘cohort的心跳則認爲crash,從而發起view change。從理論上來講,經過心跳來檢測對方server是否crash是不可靠的,主要是單憑心跳時間,沒法區分crash和busy,這個值的設 定跟應用所處的網絡環境有很大關係。固然也可引入其餘更復雜的crash檢測機制,就不在這裏做深刻討論。
如上所述,當某個cohort經過心跳發現對方已經crash時,就發起view change,可能會有多個cohort同時發起view change,因此必須保證只能創建一個新的view,基本方法以下:(假如A、B、C同時發現D失敗)
1. A構造一個新的viewid,這個view id要比A所見到的全部的view id都大,而且不一樣的cohort生的view id必定不能相同,這點與paxos的proposalid很是像
2. A發送一個invitation到其餘活着的cohort,好比X
3. X發現A發送的view id,比本身所見到的全部view id都大,因而接收邀請並回復給A;不然,X拒絕A,不作任何迴應。
4. A在接收到多數派的迴應後,認爲新的view已經造成,初始化新的primary;不然,沒法造成新的view,一段時間後改變view id重複上述過程
在4中只是說,接收到多數派的迴應,就認爲新的view已經造成,要達到這個目標必須知足兩個充分條件:
第一個條件比較容易驗證,由於在Viewstamps算法中假定viewstamps的記錄沒有持久化,因此第二個條件不老是成立,好比:
此時的現狀是:A、C能夠連通,但都沒有viewstamps記錄,因此沒法造成新view;B有viewstamps記錄,但沒法與A、C互通,因此也沒法造成新View。所以可否造成新view須要下面三個增強條件:
在造成新view後,還要繼續:
5.A尋找新的primary,並把各cohort迴應的viewstamp發送給primary初始化其狀態,若是老的primary沒有crash,能夠繼續指定爲primary;不然隨機指定cohort做爲primary
6. 新Primary把在初始化時,把全部正確的viewstamp發送到全部的cohort,使全部的cohort狀態一致。
整個過程大概如此。
在6中的過程可能有多個cohort同時執行,好比A、B同時進行view change,因此該問題本質上仍是一個選舉的問題,只是對於paxos來講,是多個proposer同時proposal選擇最終決議,而如今是選擇新的view。
在paxos算法中使用了2個phase解決選舉的惟一性問題,而上述viewstamps的過程本質上就是paxos的phase 1,但僅憑phase1是沒法達成最終決議,viewstamps 算法可能並無意識到這一點,只是認爲編號高的view會被最終選擇,並提出了一些避免view change併發執行的方案。由此也可看出,paxos 算法理論上比viewstamps 更完善,也有更清晰的2phase的劃分。
還有一個關鍵問題是view在算法過程當中起了什麼做用,若是沒有view change而僅使用一個view是否能夠?在原論文中做者提到了用view的緣由:
Over time thecommunication capability within a group may change as cohorts or communicationlinks fail and recover. To reflect this changing situation, each cohort runs ina view.
就是說,由於節點、網絡都會失敗、恢復,爲了反映這一狀況每一個節點須要運行在一個view中。
從實際應用狀況來看,view反映的是節點某個時刻的運行快照,在每次新primary被選出時,須要使用正常的節點初始化其狀態,但不須要全部正常節點的數據,只須要其最後一個view的viewstamps便可,若是僅採用一個view,就會每次把全部的數據都發送的新primary。
還有一種狀況是網絡失敗,好比A、B、C三個節點,在發生網絡分區,C與A、B隔離,通過一段時間網絡分區修復,A、B、C又從新聯通,但C上的數 據已經與A、B不一致,當再進行primary選舉時就沒法判斷C上的數據是否可用。若是引入一個view,當C網絡分區時,A、B會有新的 viewid,而分區修復時,根據viewid能明確區分出C上的數據不是最新數據。因此,引入view就是爲節點引入了一個判斷數據是不是最新的標誌。
這也就證實了,在primary-backup模式中,當發生primary切換的時候,若是沒有必定的分佈式算法,僅靠backup上的數據是無 法保證新的primary能正確同步以前的狀態,也就是說任何想僅經過backup去保證primary數據正確性的作法都是徒勞。
並非每次cohort失敗都須要致使view change,若是primary沒有失敗,而僅backup失敗,且失敗後的cohort仍能構成多數派,則無需view change。但primary失敗則須要view change。viewchange的過程與primary是無關的,primary的指定也是隨機的,那爲何primary失敗缺要致使view change?其實primary切換須要2步工做:
重要的是第一步工做,只要第一步完成了,選擇哪一個cohort做爲primary都不是問題。因此,表面上primary與viewchange無關,其實view change的過程就是特爲primary而準備。這樣是viewstamps成爲選舉算法的緣由。
Viewstams 並無從理論上完整解決選舉問題,但卻爲leader選舉及選舉後的leader狀態同步提出了完整的方案。
相比而言,paxos理論上更完善,2 phase的表述也更清晰,但很顯然的是viewstamps不徹底等同與paxos,而只是作了paxos的phase 1。
Google chubby的人曾說,全部的分佈式算法都是paxos的一個特例,信矣!