1. 程式人生 > >Paxos演算法——前世

Paxos演算法——前世

    Paxos演算法是基於訊息傳遞且具有高度容錯特性的一致性演算法。我們將從一個簡單的問題開始,逐步的改進我們的設計方案,最終得到Paxos,一個可以在逆境下工作的協議。

一、客戶端-伺服器模型

    我們從最小的分散式系統開始,在這個系統中,只有兩個結點,客戶端結點與服務端結點,客戶端結點能夠操作(儲存或更新)遠端伺服器結點上的資料。

演算法1.1  樸素的客戶端/伺服器演算法:客戶端每次向伺服器傳送一條命令。

    在存在訊息丟失的訊息傳遞模型中,該演算法卻不能很好的工作,客戶端不能確認訊息是否正確的被伺服器所接受。因此我們需要對其進行一些小的改進。

演算法1.2 待確認的客戶端/伺服器演算法

    1.客戶端向服務端傳送一條請求命令訊息。

    2.服務端接受請求並回復確認資訊。

    3.客戶端在一定的時間範圍內,沒有收到伺服器端傳送的請求確認資訊的回覆,則重新發送命令請求資訊。

  • 該演算法描述了,客戶端在傳送一條請求命令後,在收到服務端的確認回覆前,是不會發送下一條請求命令。
  • 客戶端在傳送的過程中訊息可能丟失,服務端在回覆的確認訊息時,訊息也可能丟失,對於服務端確認訊息的丟失情況,在到達一定超時時間後,客戶端未收到確認回覆,會重新發送訊息,此時該訊息已經被伺服器端處理,所以我們需要有一種機制能夠保證訊息的冪等性。例如給訊息加上序列號。
  • 該演算法可以很容易的擴充套件到多伺服器端的場景,客戶端傳送命令請求給每一個伺服器端,當收到所有伺服器的確認訊息,就可以認為這條命令執行成功。
  • 如何處理多個客戶端的場景?
    基於可變訊息延遲模型我們可以得出如下定理,即訊息的延遲時間是不定的,同一對結點的訊息傳送的時間延遲也是不同的。

定理1.1  如果演算法在多個客戶端與服務端執行,伺服器收到的命令順序可能是不同的,這會導致不一致的狀態。

    假設在如下的場景中,存在客戶端c1,c2 ,服務端 s1,s2.  服務端s1,s2存在相同的值x = 0。 如果此時 c1,向伺服器s1,s2 傳送 x = x + 1. 在同一時刻 c2 向伺服器 s1,s2 傳送 x = 2*x. 假設c1 先於 c2 到達 s1 ,則此時s1的狀態值x為 2, 而 c2 先於 c1 到達 s2 , 則此時 s2 的狀態值x為 1. 導致叢集的狀態不一致。

定義1.1  (狀態複製)對於一組結點,如果所有結點都以相同的順序執行命令序列 c1,c2,c3,c4……,則這組結點實現了狀態複製

  • 狀態複製是分散式系統的基本特徵
  • 因為單個系統天然實現狀態複製,可以令單個伺服器系統實現序列化器,自動對請求進行排序來分發命令,從而實現狀態複製。

演算法1.3 藉助單一的序列化器實現狀態複製

    1. 所有的客戶端將請求命令傳送到序列化器

    2.序列化器逐個處理客戶端請求,並將客戶端請求逐個傳送給所有伺服器

    3.當序列化器接受到所有伺服器的確認訊息時,它將返回給對應客戶端命令執行成功的訊息。

  • 這個想法有時也被成為主從複製。
  • 改演算法存在單點故障。序列化器
  • 我們是否可以構造一個更分散式的方法來解決狀態複製的問題。去掉序列化器。任何時刻最多隻有一個結點可以傳送請求命令,是否可以採用互斥或各自加鎖的思想?

演算法 1.4 兩階段鎖

    階段 1  :

          客戶端向所有伺服器請求獲取鎖

    階段 2: 

          if   客戶端獲得所有伺服器的加鎖請求 

               客戶端以可靠的方式向所有伺服器傳送命令請求,釋放鎖

          else 

               客戶端釋放已經獲取的鎖,休眠一段時間,進入階段 1 

 

  • 演算法 1.4 是否能夠很好的應對結點崩潰呢?在該演算法中要求所有的伺服器結點都必須能夠正常的工作
  • 如果僅獲取部分伺服器的鎖能否工作,獲得過半數伺服器的鎖是否就足夠了?
  • 如果超過兩個以上的客戶端試圖獲取超過半數伺服器的鎖,怎麼應對死鎖的問題,是否需要釋放已經獲取的伺服器鎖,如果客戶端在釋放鎖之前就發生了故障,怎麼辦,是否需要一個與鎖不同的概念。