1. 程式人生 > >通俗理解ZooKeeper是如何保證資料一致性的

通俗理解ZooKeeper是如何保證資料一致性的

ZooKeeper是個叢集,內部有多個server,每個server都可以連線多個client,每個client都可以修改server中的資料
ZooKeeper可以保證每個server內的資料完全一致,是如何實現的呢?

答:資料一致性是靠Paxos演算法保證的,Paxos可以說是分散式一致性演算法的鼻祖,是ZooKeeper的基礎

假設有一個社團,其中有團員、議員(決議小組成員)兩個角色

團員可以向議員申請提案來修改社團制度

議員坐在一起,拿出自己收到的提案,對每個提案進行投票表決,超過半數通過即可生效
為了秩序,規定每個提案都有編號ID,按順序自增

每個議員都有一個社團制度筆記本,上面記著所有社團制度,和最近處理的提案編號,初始為0
投票通過的規則:

新提案ID 是否大於 議員本中的ID,議員舉手贊同

如果舉手人數大於議員人數的半數,即讓新提案生效

例如:
剛開始,每個議員本子上的ID都為0,現在有一個議員拿出一個提案:團費降為100元,這個提案的ID自增為1

每個議員都和自己ID對比,一看 1>0,舉手贊同,同時修改自己本中的ID為1

發出提案的議員一看超過半數同意,就宣佈:1號提案生效

然後所有議員都修改自己筆記本中的團費為100元
以後任何一個團員諮詢任何一個議員:"團費是多少?",議員可以直接開啟筆記本檢視,並回答:團費為100元
可能會有極端的情況,就是多個議員一起發出了提案,就是併發的情況

例如
剛開始,每個議員本子上的編號都為0,現在有兩個議員(A和B)同時發出了提案,那麼根據自增規則,這兩個提案的編號都為1,但只會有一個被先處理

假設A的提案在B的上面,議員們先處理A提案並通過了,這時,議員們的本子上的ID已經變為了1,接下來處理B的提案,由於它的ID是1,不大於議員本子上的ID,B提案就被拒絕了,B議員需要重新發起提案

上面就是Paxos的基本思路,對照ZooKeeper,對應關係就是:
團員 -client
議員 -server
議員的筆記本 -server中的資料
提案 -變更資料的請求
提案編號 -zxid(ZooKeeper Transaction Id)
提案生效 -執行變更資料的操作
ZooKeeper中還有一個leader的概念,就是把發起提案的權利收緊了,以前是每個議員都可以發起提案,現在有了leader,大家就不要七嘴八舌了,先把提案都交給leader,由leader一個個發起提案
Paxos演算法就是通過投票、全域性編號機制,使同一時刻只有一個寫操作被批准,同時併發的寫操作要去爭取選票,只有獲得過半數選票的寫操作才會被批准,所以永遠只會有一個寫操作得到批准,其他的寫操作競爭失敗只好再發起一輪投票

1)一致性保證

Zookeeper 是一種高效能、可擴充套件的服務。 Zookeeper 的讀寫速度非常快,並且讀的速度要比寫的速度更快。另外,在進行讀操作的時候, ZooKeeper 依然能夠為舊的資料提供服務。這些都是由於 ZooKeepe 所提供的一致性保證,它具有如下特點:

順序一致性

客戶端的更新順序與它們被髮送的順序相一致。

原子性

更新操作要麼成功要麼失敗,沒有第三種結果。

單系統映象

無論客戶端連線到哪一個伺服器,客戶端將看到相同的 ZooKeeper 檢視。

可靠性

一旦一個更新操作被應用,那麼在客戶端再次更新它之前,它的值將不會改變。。這個保證將會產生下面兩種結果:

1 .如果客戶端成功地獲得了正確的返回程式碼,那麼說明更新已經成果。如果不能夠獲得返回程式碼(由於通訊錯誤、超時等等),那麼客戶端將不知道更新操作是否生效。

2 .當從故障恢復的時候,任何客戶端能夠看到的執行成功的更新操作將不會被回滾。

實時性

在特定的一段時間內,客戶端看到的系統需要被保證是實時的(在十幾秒的時間裡)。在此時間段內,任何系統的改變將被客戶端看到,或者被客戶端偵測到。

給予這些一致性保證, ZooKeeper 更高階功能的設計與實現將會變得非常容易,例如: leader 選舉、佇列以及可撤銷鎖等機制的實現。

2)Leader選舉

ZooKeeper 需要在所有的服務(可以理解為伺服器)中選舉出一個 Leader ,然後讓這個 Leader 來負責管理叢集。此時,叢集中的其它伺服器則成為此 Leader  Follower 。並且,當 Leader 故障的時候,需要 ZooKeeper能夠快速地在 Follower 中選舉出下一個 Leader 。這就是 ZooKeeper  Leader 機制,下面我們將簡單介紹在ZooKeeper 中, Leader 選舉( Leader Election )是如何實現的。

此操作實現的核心思想是:首先建立一個 EPHEMERAL 目錄節點,例如“ /election ”。然後。每一個ZooKeeper 伺服器在此目錄下建立一個 型別的節點,例如“ /election/n_ ”。在SEQUENCE 標誌下, ZooKeeper 將自動地為每一個 ZooKeeper 伺服器分配一個比前一個分配的序號要大的序號。此時建立節點的 ZooKeeper 伺服器中擁有最小序號編號的伺服器將成為 Leader 

在實際的操作中,還需要保障:當 Leader 伺服器發生故障的時候,系統能夠快速地選出下一個 ZooKeeper 伺服器作為 Leader 。一個簡單的解決方案是,讓所有的 follower 監視 leader 所對應的節點。當 Leader 發生故障時, Leader 所對應的臨時節點將會自動地被刪除,此操作將會觸發所有監視 Leader 的伺服器的 watch 。這樣這些伺服器將會收到 Leader 故障的訊息,並進而進行下一次的 Leader 選舉操作。但是,這種操作將會導致“從眾效應”的發生,尤其當叢集中伺服器眾多並且頻寬延遲比較大的時候,此種情況更為明顯。

 Zookeeper 中,為了避免從眾效應的發生,它是這樣來實現的:每一個 follower  follower 叢集中對應的比自己節點序號小一號的節點(也就是所有序號比自己小的節點中的序號最大的節點)設定一個 watch 。只有當follower 所設定的 watch 被觸發的時候,它才進行 Leader 選舉操作,一般情況下它將成為叢集中的下一個 Leader。很明顯,此 Leader 選舉操作的速度是很快的。因為,每一次 Leader 選舉幾乎只涉及單個 follower 的操作。