1. 程式人生 > >Zookeeper深入分析

Zookeeper深入分析

前言

zookeeper 是一個開源的分散式協調服務,由雅虎公司建立,是google chubby的開源實現,是Hadoop和Hbase的重要元件。它是一個為分散式應用提供一致性服務的軟體,提供的功能包括:配置維護、域名服務、分散式同步、組服務等。zookeeper的設計目 標是將哪些複雜且容易出錯的分散式一致性服務封裝起來, 構成一個高效可靠的原語集(由若干條指令組成的,完成 一定功能的一個過程),並且以一系列簡單易用的介面提供給使用者使用 。
在分散式架構下,當服務越來越多,規模越來越大時,對 應的機器數量也越來越大,單靠人工來管理和維護服務及 地址的配置地址資訊會越來越困難,單點故障的問題也開 始凸顯出來,一旦服務路由或者負載均衡伺服器宕機,依 賴他的所有服務均將失效。 此時,需要一個能夠動態註冊和獲取服務資訊的地方來統一管理服務名稱和其對應的伺服器列表資訊,稱之為 服務配置中心,服務提供者在啟動時,將其提供的服務名 稱、伺服器地址註冊到服務配置中心,服務消費者通過服 務配置中心來獲得需要呼叫的服務的機器列表。通過相應 的負載均衡演算法,選取其中一臺伺服器進行呼叫。當服務 器宕機或者下線時,相應的機器需要能夠動態地從服務配 置中心裡面移除,並通知相應的服務消費者,否則服務消費者就有可能因為呼叫到已經失效服務而發生錯誤,在這 個過程中,服務消費者只有在第一次呼叫服務時需要查詢 服務配置中心,然後將查詢到的資訊快取到本地,後面的 呼叫直接使用本地快取的服務地址列表資訊,而不需要重 新發起請求到服務配置中心去獲取相應的服務地址列表, 直到服務的地址列表有變更(機器上線或者下線)。這種無 中心化的結構解決了之前負載均衡裝置所導致的單點故障 問題,並且大大減輕了服務配置中心的壓力。

一.Zookeeper的設計理念

分散式系統的很多問題都是由於缺少協調機制造成的,而Google的Chubby以及Apache的Zookeeper在分散式協調方面做得比較好。 Google 的Chubby 是一個分散式鎖服務,通過 Google Chubby 來解決分散式協作、Master 選舉等與分散式鎖服務相關的問題。 但是由於當時谷歌的Chubby 是不開源的,所以後來雅虎基於 Chubby 的思想開發了 zookeeper,並捐贈給了Apache。
zookeeper 主要是解決分散式環境下的服務協調問題而產生的,它的設計主要基於以下幾點:
1.防止單點故障 :如果要防止zookeeper中介軟體的單點故障,那就必須要做叢集,而且還要是一個高效能高可用的叢集。高效能意味著這個集 群能夠分擔客戶端的請求流量,高可用意味著叢集中的 某一個節點宕機以後,不影響整個叢集的資料和繼續提 供服務的可能性。
2.如果要滿足這樣的一個高 效能叢集,那麼每個節點都要能接 收到請求,並且每個節點的資料都必須要保持一致

。要 實現各個節點的資料一致性,就勢必要一個leader節點 負責協調和資料同步操作。因為如果在一個叢集中沒有leader節點,每個節點都可以接收所有請求,那麼這個叢集的資料同步的複雜度非常大。
3.如何在這些節點中選舉出leader節點,以及 leader掛了以後,如何恢復呢?zookeeper用了基於paxos理論所衍生出來 的ZAB協議。
4.leader 節點如何和其他節點保證資料一致性,並且要求 是強一致的。在分散式系統中,每一個機器節點雖然都 能夠明確知道自己進行的事務操作過程是成功和失敗, 但是卻無法直接獲取其他分散式節點的操作結果。所以 當一個事務操作涉及到跨節點的時候,就需要用到分佈 式事務,分散式事務的資料一致性協議有 2PC 協議和 3PC協議。

二.2PC協議

2PC協議,(Two Phase Commitment Protocol)當一個事務操作需要跨越多個分散式節點的時候,為了保持事務處理的ACID 特性,就需要引入一個“協調者”(TM)來統一排程所有分 布式節點的執行邏輯,這些被排程的分散式節點被稱為AP。 TM負責排程AP的行為,並最終決定這些AP是否要把事 務真正進行提交,因為整個事務是分為兩個階段提交,所 以叫2pc 。
如下圖,詳細闡述了這個過程:
在這裡插入圖片描述
階段一:提交事務請求(投票)
1.事務詢問
協調者向所有的參與者傳送事務內容,詢問是否可以執行事 務提交操作,並開始等待各參與者的響應 。
2.執行事務的各個參與者節點執行事務操作,並將Undo和Redo資訊記 錄到事務日誌中,儘量把提交過程中所有消耗時間的操作都準備好提前完成,確保後面100%成功提交事務。
3. 各個參與者向協調者反饋事務詢問的響應, 如果各個參與者成功執行了事務操作,那麼就反饋給參與者 yes的響應,表示事務可以執行;如果參與者沒有成功執行 事務,就反饋給協調者 no 的響應,表示事務不可以執行,這個階段有點類似協調者組織各個參與者對一次事務 操作的投票表態過程,因此 2pc 協議的第一個階段稱為“投票階段”,即各參與者投票表明是否需要繼續執行接下去的 事務提交操作。
階段二:執行事務提交
協調者會根據各參與者的反饋情況來決定最終是否可以進行事務提交操作,正常情況下包含兩種可能:提交事務,回滾事務。

三.Zookeeper的叢集

在zookeeper中,客戶端會隨機連線到zookeeper叢集中 的一個節點,如果是讀請求,就直接從當前節點中讀取數 據,如果是寫請求,請求會被轉發給leader提交事務, 然後 leader 會廣播事務,只要有超過半數節點寫入成功, 寫請求才會被提交(類似於2PC事務)。
所有事務請求必須由一個全域性唯一的伺服器來協調處理,這個伺服器就是 Leader 伺服器,其他的伺服器就是follower。leader伺服器把客戶端的請求轉化成一個事務 Proposal(提議),並把這個 Proposal 分發給叢集中的所有 Follower 伺服器。之後 Leader 伺服器需要等待所有Follower伺服器的反饋,一旦超過半數的Follower伺服器進行了正確的反饋,那麼 Leader 就會再次向所有的Follower伺服器傳送Commit訊息,要求各個follower節點對前面的一個Proposal進行提交。
1.叢集角色
Leader 角色
Leader伺服器是整個zookeeper叢集的核心,主要的工作 任務有兩項 :1. 事物請求的唯一排程和處理者,保證叢集事務處理的順 序性; 2. 叢集內部各伺服器的排程者。
Follower 角色
Follower角色的主要職責是: 1. 處理客戶端非事物請求、轉發事物請求給leader伺服器; 2. 參與事物請求 Proposal 的投票(需要半數以上伺服器 通過才能通知leader commit資料; Leader發起的提案, 要求Follower投票); 3. 參與Leader選舉的投票
Observer 角色
Observer 是 zookeeper3.3 開始引入的一個全新的伺服器 角色,從字面來理解,該角色充當了觀察者的角色。 觀察zookeeper叢集中的最新狀態變化並將這些狀態變化 同步到 observer 伺服器上。Observer 的工作原理與 follower 角色基本一致,而它和 follower 角色唯一的不同 在於 observer 不參與任何形式的投票,包括事物請求 Proposal的投票和leader選舉的投票。即observer 伺服器只提供非事物請求服務,通常是在不影響叢集事物 處理能力的前提下提升叢集非事物處理的能力 。
2.叢集組成
通常zookeeper是由2n+1臺server組成,每個server都 知道彼此的存在。對於2n+1臺server,只要有n+1臺(大 多數)server可用,整個系統就保持可用。一個zookeeper叢集如果要對外提供可用的服務,那麼集 群中必須要有過半的機器正常工作並且彼此之間能夠正常 通訊,基於這個特性,如果想搭建一個能夠允許 F 臺機器 宕掉的叢集,那麼就要部署 2*F+1 臺伺服器構成的 zookeeper 叢集。因此 一個 5 臺機器叢集 的服務,能夠對 2 臺機器掛掉的情況下進行容災。如果是一個由6臺服務構成的叢集,同樣只能掛掉2臺機器。因此, 5 臺和 6 臺在容災能力上並沒有明顯優勢,反而增加了網 絡通訊負擔。系統啟動時,叢集中的server會選舉出一臺 server為Leader,其它的就作為follower(這裡先不考慮 observer角色)。 之所以要滿足這樣一個等式,是因為一個節點要成為叢集 中的 leader,需要有超過叢集中過半數的節點支援,這個 涉及到leader選舉演算法。同時也涉及到事務請求的提交投 票 過程。

四.ZAB協議

ZAB(Zookeeper Atomic Broadcast) 協議是為分散式協 調服務 ZooKeeper 專門設計的一種支援崩潰恢復的原子 廣播協議。在 ZooKeeper 中,主要依賴 ZAB 協議來實現 分散式資料一致性,基於該協議,ZooKeeper 實現了一種 主備模式的系統架構來保持叢集中各個副本之間的資料一 致性。
1.zab 協議介紹
ZAB協議包含兩種基本模式,分別是: 1. 崩潰恢復 2. 原子廣播
當整個叢集在啟動時,或者當 leader 節點出現網路中斷、 崩潰等情況時,ZAB 協議就會進入恢復模式並選舉產生新 的Leader,當 leader伺服器選舉出來後,並且叢集中有過 半的機器和該leader節點完成資料同步後(同步指的是數 據同步,用來保證叢集中過半的機器能夠和leader伺服器 的資料狀態保持一致),ZAB協議就會退出恢復模式。 當叢集中已經有過半的 Follower 節點完成了和 Leader 狀 態同步以後,那麼整個叢集就進入了訊息廣播模式。這個 時候,在Leader節點正常工作時,啟動一臺新的伺服器加 入到叢集,這個伺服器會直接進入資料恢復模式,和 leader 節點進行資料同步。同步完成後即可正常對外提供 非事務請求的處理。
2.訊息廣播的實現原理
訊息廣播的過程實際上是一個 簡化版的二階段提交過程: 1. leader 接收到訊息請求後,將訊息賦予一個全域性唯一的 64位自增id(zxid),通過zxid的大小比較就可以實現因果有序; 2. leader為每個follower準備了一個FIFO佇列(通過TCP 協議來實現,以實現了全域性有序的特點),將帶有zxid的訊息作為一個提案(proposal)分發給所有的follower ;3. 當follower接收到proposal,先把proposal寫到磁碟, 寫入成功以後再向leader回覆一個ack ;4. 當leader接收到合法數量(超過半數節點)的ACK後, leader就會向這些follower傳送commit命令,同時會 在本地執行該訊息 ;5. 當 follower 收到訊息的 commit命令以後,會提交該訊息 。
leader 的投票過程,不需要 Observer 的 ack,也就是 Observer不需要參與投票過程,但是Observer必須要同 步 Leader 的資料從而在處理請求的時候保證資料的一致 性 。
3.崩潰恢復(資料恢復)
ZAB 協議基於原子廣播協議的訊息廣播過程,在正 常情況下是沒有任何問題的,但是一旦 Leader 節點崩潰, 或者由於網路問題導致 Leader 伺服器失去了過半的Follower節點的聯絡(leader失去與過半follower節點聯 系,可能是leader節點和follower節點之間產生了網路分 區,那麼此時的leader不再是合法的leader了),那麼就 會進入到崩潰恢復模式。在ZAB協議中,為了保證程式的 正確執行,整個恢復過程結束後需要選舉出一個新的 Leader, 為了使 leader 掛了後系統能正常工作,需要解決以下兩 個問題: 1. 已經被處理的訊息不能丟失, 當 leader 收到合法數量 follower 的 ACKs 後,就向 各個 follower 廣播 COMMIT 命令,同時也會在本地 執行 COMMIT 並向連線的客戶端返回「成功」。但是如 果在各個 follower 在收到 COMMIT 命令前 leader 就掛了,導致剩下的伺服器並沒有執行這條訊息。
leader 對事務訊息發起 commit 操作,但是該訊息在 follower1 上執行了,但是 follower2 還沒有收到 commit, 就已經掛了,而實際上客戶端已經收到該事務訊息處理成功的回執了。所以在zab協議下需要保證所有機器都要執 行這個事務訊息 2. 被丟棄的訊息不能再次出現 ,當 leader 接收到訊息請求生成 proposal 後就掛了,其他 follower 並沒有收到此 proposal,因此經過恢復模式重新選了 leader 後,這條訊息是被跳過的。 此時,之前掛了的 leader 重新啟動並註冊成了 follower,他保留了被跳過訊息的 proposal 狀態,與整個系統的狀態是不一致的,需要將其刪除。
總結:ZAB 協議需要滿足上面兩種情況,就必須要設計一個 leader 選舉演算法:能夠確保已經被 leader 提交的事務 Proposal能夠提交、同時丟棄已經被跳過的事務Proposal。 針對這個要求 1. 如果 leader 選舉演算法能夠保證新選舉出來的 Leader 服 務器擁有叢集中所有機器最高編號(ZXID最大)的事務 Proposal,那麼就可以保證這個新選舉出來的Leader一 定具有已經提交的提案。因為所有提案被 COMMIT 之 前必須有超過半數的 follower ACK,即必須有超過半數 節點的伺服器的事務日誌上有該提案的 proposal,因此,只要有合法數量的節點正常工作,就必然有一個節點保 存了所有被 COMMIT 訊息的 proposal 狀態 ; 另外zxid是64位,高32位是epoch編號,每經過 一次 Leader 選舉產生一個新的 leader,新的 leader 會將 epoch 號+1,低 32 位是訊息計數器,每接收到一條訊息 這個值+1,新 leader選舉後這個值重置為0.這樣設計的好 處在於老的leader掛了以後重啟,它不會被選舉為leader, 因此此時它的 zxid 肯定小於當前新的 leader。當老的 leader 作為 follower 接入新的 leader 後,新的 leader 會 讓它將所有的擁有舊的 epoch 號的未被 COMMIT 的 proposal 清除 。
4.ZXID
zxid就是事務id, 為了保證事務的順序一致性,zookeeper 採用了遞增的事 務 id 號(zxid)來標識事務。所有的提議(proposal)都 在被提出的時候加上了 zxid。實現中 zxid 是一個 64 位的 數字,它高32位是epoch(ZAB協議通過epoch編號來 區分 Leader 週期變化的策略)用來標識 leader 關係是否 改變,每次一個 leader 被選出來,它都會有一個新的 epoch=(原來的epoch+1),標識當前屬於那個leader的 統治時期。低32位用於遞增計數。

epoch :可以理解為當前叢集所處的年代或者週期, leader 變更之後,都會在前一個年代的基礎上加 1 。這樣 就算舊的 leader 崩 潰 恢 復 之 後 ,也 沒 有 人 聽 他 的 了 ,因 為 follower 只聽從當前年代的 leader 的命令。

五.leader 選舉

Leader選舉分兩個過程: 啟動的時候的leader選舉、 leader崩潰的時候的選舉
1.伺服器啟動時的 leader 選舉
每個節點啟動的時候狀態都是 LOOKING,處於觀望狀態, 接下來就開始進行選舉流程
進行Leader選舉,至少需要兩臺機器 ,這裡以3臺機器組成的伺服器叢集為例,在集 群初始化階段,當有一臺伺服器Server1啟動時,它本身是 無法進行和完成Leader選舉,當第二臺伺服器Server2啟 動時,這個時候兩臺機器可以相互通訊,每臺機器都試圖 找到Leader,於是進入Leader選舉過程。選舉過程如下 (1) 每個Server發出一個投票,由於是初始情況,Server1 和 Server2 都會將自己作為 Leader 伺服器來進行投 票,每次投票會包含所推舉的伺服器的myid和ZXID、 epoch,使用(myid, ZXID,epoch)來表示,此時Server1 的投票為(1, 0),Server2的投票為(2, 0),然後各自將 這個投票發給叢集中其他機器。 (2) 接受來自各個伺服器的投票。叢集的每個伺服器收到 投票後,首先判斷該投票的有效性,如檢查是否是本 輪投票 (epoch)、是否來自LOOKING狀態的伺服器。 (3) 處理投票。針對每一個投票,伺服器都需要將別人的 投票和自己的投票進行PK,PK規則如下 i. 優先檢查 ZXID。ZXID 比較大的伺服器優先作為 Leader ;
ii. 如果ZXID相同,那麼就比較myid。myid較大的 伺服器作為Leader伺服器。 對於 Server1 而言,它的投票是(1, 0),接收 Server2 的投票為(2, 0),首先會比較兩者的ZXID,均為0,再 比較myid,此時Server2的myid最大,於是更新自 己的投票為(2, 0),然後重新投票,對於Server2而言, 它不需要更新自己的投票,只是再次向叢集中所有機 器發出上一次投票資訊即可。 (4) 統計投票。每次投票後,伺服器都會統計投票資訊, 判斷是否已經有過半機器接受到相同的投票資訊,對 於Server1、Server2而言,都統計出叢集中已經有兩 臺機器接受了(2, 0)的投票資訊,此時便認為已經選出 了Leader。 (5) 改變伺服器狀態。一旦確定了Leader,每個伺服器就 會更新自己的狀態,如果是Follower,那麼就變更為 FOLLOWING,如果是Leader,就變更為LEADING。
2.執行過程中的 leader 選舉
當叢集中的 leader 伺服器出現宕機或者不可用的情況時, 那麼整個叢集將無法對外提供服務,而是進入新一輪的 Leader 選舉,伺服器執行期間的 Leader 選舉和啟動時期 的Leader選舉基本過程是一致的。
(1) 變更狀態。Leader掛後,餘下的非Observer伺服器 都會將自己的伺服器狀態變更為 LOOKING,然後開 始進入Leader選舉過程。 (2) 每個Server會發出一個投票。在執行期間,每個服務 器上的ZXID可能不同,此時假定Server1的ZXID為 123,Server3的ZXID為122;在第一輪投票中,Server1 和Server3都會投自己,產生投票(1, 123),(3, 122), 然後各自將投票傳送給叢集中所有機器。接收來自各 個伺服器的投票。與啟動時過程相同。 (3) 處理投票。與啟動時過程相同,此時,Server1將會成 為Leader。 (4) 統計投票。與啟動時過程相同。 (5) 改變伺服器的狀態。與啟動時過程相同 。

上一篇:http,https協議