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