viewstamp replication: A new primary copy method to support highly-avaliable d

爲了提升服務能力或者服務穩定,每每須要把數據重複佈署,也就是replication。重複帶來的問題是,更新的時候會帶來不一致。一種比較簡單的方法是,在N臺重複的機器裏選一臺做爲主機,其餘做備份,只能經過主機更新,主機更新完全部備機後,才向上層應用返回成功。若是主機故障,則從備機中挑一臺做爲新的主機,這須要用到選舉算法。

這裏存在幾個問題,一是主機崩潰前的最後一個操做進行到哪了,二是網絡分隔的時候,會選出多臺主機,三是有的備機曾經發生過故障,上面的數據不是最新的,不能做爲主機。html

viewstampedreplication能夠解決上面三個問題算法

view的含義是,能夠互相聯繫的K臺機器,以及主機ID,要求K大於集羣中總機器數的一半。當有新的機器加入,或者有機器故障,或者更換主機,則變成另外一個VIEW了。數據庫

必須一個VIEW中全部的機器都成功,該操做纔算成功。VIEW中每臺機器都記錄最新一次操做的VIEWID及操做的時間戳。這樣,就能夠知道最後一個操做進行到哪了。由於K要求佔大多數,因此不會出現多個VIEW。根據每臺機器的記錄,選擇最新的一個,就能夠知道哪些機器的數據不是最新的。網絡

 

 

()Viewstamps算法併發

Viewstamps算法

1. 前言

Viewstamps算法是Oki和Liskov於1988年發表的論文,Liskov是一位計算機世界中傑出的女性,08年圖靈獎得主、著名面向 對象五原則中「Liskov可替換原則」的提出者。咱們已無精力考證Viewstamps是不是第一個多數派表決的算法,但知道其比 Paxos(1998)整整早了10年,杯具的是,隨着06年googlechubby論文發表,Paxos迅速聞名於世,而Viewstamps依舊寂寂無聞。分佈式

2. 問題的由來

在分佈式系統中通常經過複製來提升系統的可用性,而複製又引入了一致性的問題,好比咱們把數據複製到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的選舉算法。優化

3. 概念

  • Primary Service被複制(部署)多份,每份複製稱爲backup,primary與衆多的backup組成一個group,提供與一個primary相同的邏輯功能。
  • group裏的每一個成員又被稱爲cohort,cohort能夠是primary也能夠是backup。
  • group裏的所有cohor又稱爲configuration,group更可能是描述性的稱呼,而configuration是指要在配置文件中把這個關係固定下來,是配置性的稱呼。
  • configuration中超過1/2的成員又稱爲多數派(majority),viewstamps容許2N+1個節點中的N個節點同時失敗。
  • 在某一時刻,系統的狀態是有一個primary與幾個backup提供服務(未必是全部的backup),這種狀態稱爲view。
  • 在某個primary或backup crash後,這個view就會被打破,從而造成新的view,這個過程叫view change,而viewstamps又自稱爲view change算法。

另外補充幾個次重要概念:this

  • 每一個group都有一個groupid,是配置好的,不能更改
  • 每一個view都有一個viewid,動態生成
  • 每一個cohort都有一個惟一的id
  • 每一個primary都有一個queue用來保證數據一致性,queue中的數據按照timestamp的順序(前後順序)保持數據
  • primary每次與backup通訊稱爲event
  • 每一個event一定發生在某個view中,event又是根據timestamps的順序傳遞數據,所以算法叫viewstamps。
  • 事務:viewstamps 中的事務實現方式都是二段提交,即prepare和commit兩個階段。

存在衆多繁雜且表述不一的概念,也是viewstamps算法的一大特點,翻來覆去就那麼幾樣東西,你們習慣便可。google

4. 調用過程

客戶端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個節點失敗。

5. 節點失敗

cohort失敗的狀況比較多,但假定數據能夠丟失、複製、亂序,但不能出現拜占庭問題,即不能篡改消息;另假設全部的失敗都是fail-stop,即失敗中止,不會在失敗狀態繼續服務。雖然假設感受比較多,但這些假設通常的通訊環境都能知足。

節點會有下面幾種失敗狀態:

  • 失敗致使service沒法訪問
  • 失敗後又甦醒,丟失以前的狀態
  • 網絡失敗致使分區,好比致使cohort被分紅兩組,組以內的cohort能夠相互訪問,組之間的不能,典型的發生場景是交換機發生問題。

前兩種錯誤會致使view change;後一種失敗由於採用強制多數派的機制,保證了雖然有一個少數派的網絡存在,但由於沒法造成多數派而沒法工做,就杜絕了存在兩個viewstamps group同時工做帶來的風險。

通常咱們會在cohort之間保持心跳檢測,一旦某個cohort在指定的時間沒有收到其餘cohort的心跳則認爲crash,從而發起view change。從理論上來講,經過心跳來檢測對方server是否crash是不可靠的,主要是單憑心跳時間,沒法區分crash和busy,這個值的設 定跟應用所處的網絡環境有很大關係。固然也可引入其餘更復雜的crash檢測機制,就不在這裏做深刻討論。

6. View change

如上所述,當某個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已經造成,要達到這個目標必須知足兩個充分條件:

  • 存在一個多數派cohort接收了inviitation
  • 而且這個多數派中至少存在一個cohort知道以前全部的viewstamp

第一個條件比較容易驗證,由於在Viewstamps算法中假定viewstamps的記錄沒有持久化,因此第二個條件不老是成立,好比:

  • 有A(primary)、B、C三個節點,A提交事務
  • event同步到B但還未到C,A crash
  • A又迅速從crash狀態recovery
  • B與A、C發生了網絡分區

此時的現狀是:A、C能夠連通,但都沒有viewstamps記錄,因此沒法造成新view;B有viewstamps記錄,但沒法與A、C互通,因此也沒法造成新View。所以可否造成新view須要下面三個增強條件:

  • a majority of cohorts accepted normally, or
  • crash-viewid < normal-viewid, or
  • crash-viewid = normal-viewid and the primary of view normal-viewid has done a normal acceptance of the invitation.

在造成新view後,還要繼續:

    5.A尋找新的primary,並把各cohort迴應的viewstamp發送給primary初始化其狀態,若是老的primary沒有crash,能夠繼續指定爲primary;不然隨機指定cohort做爲primary
    6. 新Primary把在初始化時,把全部正確的viewstamp發送到全部的cohort,使全部的cohort狀態一致。

整個過程大概如此。

7. 併發執行

在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數據正確性的作法都是徒勞。

8. 優化

並非每次cohort失敗都須要致使view change,若是primary沒有失敗,而僅backup失敗,且失敗後的cohort仍能構成多數派,則無需view change。但primary失敗則須要view change。viewchange的過程與primary是無關的,primary的指定也是隨機的,那爲何primary失敗缺要致使view change?其實primary切換須要2步工做:

  • 準備primary切換後的數據,爲cohort造成一個新的view
  • 選擇一個cohort做爲primary

重要的是第一步工做,只要第一步完成了,選擇哪一個cohort做爲primary都不是問題。因此,表面上primary與viewchange無關,其實view change的過程就是特爲primary而準備。這樣是viewstamps成爲選舉算法的緣由。

9. 結論

Viewstams 並無從理論上完整解決選舉問題,但卻爲leader選舉及選舉後的leader狀態同步提出了完整的方案。

相比而言,paxos理論上更完善,2 phase的表述也更清晰,但很顯然的是viewstamps不徹底等同與paxos,而只是作了paxos的phase 1。

Google chubby的人曾說,全部的分佈式算法都是paxos的一個特例,信矣!

相關文章
相關標籤/搜索