zookeeper理論


第一章 Zookeeper server

1.1  Zookeeper基本原理

 

1.1.1    Zookeeper的保證

l         順序性,client的updates請求都會根據它發出的順序被順序的處理;

l         原子性,  一個update操作要么成功要么失敗,沒有其他可能的結果;

l         一致的鏡像,client不論連接到哪個server,展示給它都是同一個視圖;

l         可靠性,一旦一個update被應用就被持久化了,除非另一個update請求更新了當前值

l         實時性,對於每個client它的系統視圖都是最新的

1.1.2    Zookeeper server角色

領導者(Leader) : 領導者不接受client的請求,負責進行投票的發起和決議,最終更新狀態。

跟隨者(Follower): Follower用於接收客戶請求並返回客戶結果。參與Leader發起的投票。

觀察者(observer): Oberserver可以接收客戶端連接,將寫請求轉發給leader節點。但是Observer不參加投票過程,只是同步leader的狀態。Observer為系統擴展提供了一種方法。

學習者 ( Learner ) : 和leader進行狀態同步的server統稱Learner,上述Follower和Observer都是Learner。

1.1.3    Zookeeper集群

 

通常Zookeeper由2n+1台servers組成,每個server都知道彼此的存在。每個server都維護的內存狀態鏡像以及持久化存儲的事務日志和快照。對於2n+1台server,只要有n+1台(大多數)server可用,整個系統保持可用。

系統啟動時,集群中的server會選舉出一台server為Leader,其它的就作為follower(這里先不考慮observer角色)。接着由follower來服務client的請求,對於不改變系統一致性狀態的讀操作,由follower的本地內存數據庫直接給client返回結果;對於會改變系統狀態的更新操作,則交由Leader進行提議投票,超過半數通過后返回結果給client。

二.Zookeeper server工作原理

Zookeeper的核心是原子廣播,這個機制保證了各個server之間的同步。實現這個機制的協議叫做Zab協議。Zab協議有兩種模式,它們分別是恢復模式和廣播模式。當服務啟動或者在領導者崩潰后,Zab就進入了恢復模式,當領導者被選舉出來,且大多數server的完成了和leader的狀態同步以后,恢復模式就結束了。狀態同步保證了leader和server具有相同的系統狀態。

一旦leader已經和多數的follower進行了狀態同步后,他就可以開始廣播消息了,即進入廣播狀態。這時候當一個server加入zookeeper服務中,它會在恢復模式下啟動,發現leader,並和leader進行狀態同步。待到同步結束,它也參與消息廣播。Zookeeper服務一直維持在Broadcast狀態,直到leader崩潰了或者leader失去了大部分的followers支持。

Broadcast模式極其類似於分布式事務中的2pc(two-phrase commit 兩階段提交):即leader提起一個決議,由followers進行投票,leader對投票結果進行計算決定是否通過該決議,如果通過執行該決議(事務),否則什么也不做。

廣播模式需要保證proposal被按順序處理,因此zk采用了遞增的事務id號(zxid)來保證。所有的提議(proposal)都在被提出的時候加上了zxid。實現中zxid是一個64為的數字,它高32位是epoch用來標識leader關系是否改變,每次一個leader被選出來,它都會有一個新的epoch。低32位是個遞增計數。

當leader崩潰或者leader失去大多數的follower,這時候zk進入恢復模式,恢復模式需要重新選舉出一個新的leader,讓所有的server都恢復到一個正確的狀態。

首先看一下選舉的過程,zk的實現中用了基於paxos算法(主要是fastpaxos)的實現。具體如下:

1.每個Server啟動以后都詢問其它的Server它要投票給誰。

2.對於其他server的詢問,server每次根據自己的狀態都回復自己推薦的leader的id和上一次處理事務的zxid(系統啟動時每個server都會推薦自己)

3.收到所有Server回復以后,就計算出zxid最大的哪個Server,並將這個Server相關信息設置成下一次要投票的Server。

4.計算這過程中獲得票數最多的的sever為獲勝者,如果獲勝者的票數超過半數,則改server被選為leader。否則,繼續這個過程,直到leader被選舉出來。

此外恢復模式下,如果是重新剛從崩潰狀態恢復的或者剛啟動的的server還會從磁盤快照中恢復數據和會話信息。(zk會記錄事務日志並定期進行快照,方便在恢復時進行狀態恢復)

選完leader以后,zk就進入狀態同步過程。

1.leader就會開始等待server連接

2.Follower連接leader,將最大的zxid發送給leader

3.Leader根據follower的zxid確定同步點

4.完成同步后通知follower 已經成為uptodate狀態

5.Follower收到uptodate消息后,又可以重新接受client的請求進行服務了。

. ZookeeperServer工作流程

 

3.1.1 主線程的工作:

1. 剛開始時各個Server處於一個平等的狀態peer

2. 主線程加載配置后啟動。

3. 主線程啟動QuorumPeer線程,該線程負責管理多數協議(Quorum),並根據表決結果進行角色的狀態轉換。

4. 然后主線程等待QuorumPeer線程。

3.1.2  QuorumPeer線程

1. 首先會從磁盤恢復zkdatabase(內存數據庫),並進行快照回復。

2. 然后啟動server的通信線程,准備接收client的請求。

3. 緊接着該線程進行選舉leader准備,選擇選舉算法,啟動response線程(根據自身狀態)向其他server回復推薦的leaer。

4. 剛開始的時候server都處於looking狀態,進行選舉根據選舉結果設置自己的狀態和角色。

3.1.3 quorumPeer有幾種狀態

1. Looking: 尋找狀態,這個狀態不知道誰是leader,會發起leader選舉

2. Observing: 觀察狀態,這時候observer會觀察leader是否有改變,然后同步leader的狀態

3. Following:  跟隨狀態,接收leader的proposal ,進行投票。並和leader進行狀態同步

4. Leading:    領導狀態,對Follower的投票進行決議,將狀態和follower進行同步

當一個Server發現選舉的結果自己是Leader把自己的狀態改成Leading,如果Server推薦了其他人為Server它將自己的狀態改成Following。做Leader的server如果發現擁有的follower少於半數時,它重新進入looking狀態,重新進行leader選舉過程。(Observing狀態是根據配置設置的)。

3.2 Leader的工作流程:

 

3.2.1 Leader主線程:

1.首先leader開始恢復數據和清除session

啟動zk實例,建立請求處理鏈(Leader的請求處理鏈):PrepRequestProcessor->ProposalRequestProcessor->CommitProcessor->Leader.ToBeAppliedRequestProcessor ->FinalRequestProcessor

2.得到一個新的epoch,標識一個新的leader , 並獲得最大zxid(方便進行數據同步)

3.建立一個學習者接受線程(來接受新的followers的連接,follower連接后確定followers的zxvid號,來確定是需要對follower進行什么同步措施,比如是差異同步(diff),還是截斷(truncate)同步,還是快照同步)

4. 向follower建立一個握手過程leader->follower NEWLEADER消息,並等待直到多數server發送了ack

5. Leader不斷的查看已經同步了的follower數量,如果同步數量少於半數,則回到looking狀態重新進行leaderElection過程,否則繼續step5.

3.2.2 LearnerCnxAcceptor線程

1.該線程監聽Learner的連接

2.接受Learner請求,並為每個Learner創建一個LearnerHandler來服務

3.2.3 LearnerHandler線程的服務流程

1.檢查server來的第一個包是否為follower.info或者observer.info,如果不是則無法建立握手。

2. 得到Learner的zxvid,對比自身的zxvid,確定同步點

3.和Learner建立第二次握手,向Learner發送NEWLEADER消息

4.與server進行數據同步。

5.同步結束,知會server同步已經ok,可以接收client的請求。

6. 不斷讀取follower消息判斷消息類型

i.           如果是LEADER.ACK,記錄follower的ack消息,超過半數ack,將proposal提交(Commit)

ii.         如果是LEADER.PING,則維持session(延長session失效時間)

iii.        如果是LEADER.REQEST,則將request放入請求鏈進行處理–Leader寫請求發起proposal,然后根據follower回復的結果來確定是否commit的。最后由FinallRequestProcessor來實際進行持久化,並回復信息給相應的response給server

3.3 Follower的工作流程:

1.啟動zk實例,建立請求處理鏈:FollowerRequestProcessor->CommitProcessor->FinalProcessor

2.follower首先會連接leader,並將zxid和id發給leader

3.接收NEWLEADER消息,完成握手過程。

4.同leader進行狀態同步

5.完成同步后,follower可以接收client的連接

5.接收到client的請求,根據請求類型

l         對於寫操作, FollowerRequestProcessor會將該操作作為LEADER.REQEST發給LEADER由LEADER發起投票。

l         對於讀操作,則通過請求處理鏈的最后一環FinalProcessor將結果返回給客戶端

對於observer的流程不再贅述,observer流程和Follower的唯一不同的地方就是observer不會參加leader發起的投票。

三.關於Zookeeper的擴展

為了提高吞吐量通常我們只要增加服務器到Zookeeper集群中。但是當服務器增加到一定程度,會導致投票的壓力增大從而使得吞吐量降低。因此我們引出了一個角色:Observer。

Observers 的需求源於 ZooKeeper  follower服務器在上述工作流程中實際扮演了兩個角色。它們從客戶端接受連接與操作請求,之后對操作結果進行投票。這兩個職能在 ZooKeeper集群擴展的時候彼此制約。如果我們希望增加 ZooKeeper 集群服務的客戶數量(我們經常考慮到有上萬個客戶端的情況),那么我們必須增加服務器的數量,來支持這么多的客戶端。然而,從一致性協議的描述可以看到,增加服務器的數量增加了對協議的投票部分的壓力。領導節點必須等待集群中過半數的服務器響應投票。於是,節點的增加使得部分計算機運行較慢,從而拖慢整個投票過程的可能性也隨之提高,投票操作的會隨之下降。這正是我們在實際操作中看到的問題——隨着 ZooKeeper 集群變大,投票操作的吞吐量會下降。

所以需要增加客戶節點數量的期望和我們希望保持較好吞吐性能的期望間進行權衡。要打破這一耦合關系,引入了不參與投票的服務器,稱為 Observers。 Observers 可以接受客戶端的連接,將寫請求轉發給領導節點。但是,領導節點不會要求 Observers 參加投票。相反,Observers 不參與投票過程,僅僅和其他服務節點一起得到投票結果。

這個簡單的擴展給 ZooKeeper 的可伸縮性帶來了全新的鏡像。我們現在可以加入很多 Observers 節點,而無須擔心嚴重影響寫吞吐量。規模伸縮並非無懈可擊——協議中的一歩(通知階段)仍然與服務器的數量呈線性關系。但是,這里的穿行開銷非常低。因此可以認為在通知服務器階段的開銷無法成為主要瓶頸。

上圖顯示了一個簡單評測的結果。縱軸是從一個單一的客戶端發出的每秒鍾同步寫操作的數量。橫軸是 ZooKeeper 集群的尺寸。藍色的是每個服務器都是 voting 服務器的情況,而綠色的則只有三個是 voting 服務器,其它都是 Observers。圖中看到,擴充 Observers,寫性能幾乎可以保持不變,但如果同時擴展 voting 節點的數量的話,性能會明顯下降。顯然 Observers 是有效的。因此Observer可以用於提高Zookeeper的伸縮性。

此外Observer還可以成為特定場景下,廣域網部署的一種方案。原因有三點:1.為了獲得更好的讀性能,需要讓客戶端足夠近,但如果將投票服務器分布在兩個數據中心,投票的延遲太大會大幅降低吞吐,是不可取的。因此希望能夠不影響投票過程,將投票服務器放在同一個IDC進行部署,Observer可以跨IDC部署。2. 投票過程中,Observer和leader之間的消息、要遠小於投票服務器和server的消息,這樣遠程部署對帶寬要求就較小。3.由於Observers即使失效也不會影響到投票集群,這樣如果數據中心間鏈路發生故障,不會影響到服務本身的可用性。這種故障的發生概率要遠高於一個數據中心中機架間的連接的故障概率,所以不依賴於這種鏈路是個優點。

 

Znodes

每個節點在zookeeper中用znode表示。znodes 包含數據變更和acl變更的版本號。znode同樣包含時間戳。版本號和時間戳用來幫助zookeeper驗證緩存或者協調更新。每次znode數據發生變化都會使版本號增加。例如,每次client接受數據時都會接收到數據的版本號。當client更新或者刪除數據時必須給znode提供數據的版本號。如果提供的版本號與實際的版本號不匹配,更新操作會失敗。

znode是程序訪問的主要實體類。包含如下特性:

Watches 

  clients 可以為znode設置watch。znode發生改變將會觸發watch。當一個watch觸發,zookeeper會向client發送通知。

 

Data Access

  在namespace中存儲在每個znode上的數據發生的讀寫操作都是原子性的。讀一個znode上的全部數據或者替換掉全部數據都是原子性的。每個znode都有一個Access Contron List(ACL)用來約束哪些人可以執行相應操作。

    Zookeeper不是用來做數據庫或者存貯大對象的。相反,它只負責協調數據。數據可以來自配置表單、結構化信息等等。這些數據的有一個共同的特點那就是都很小:以Kb為測量單位。Zookeeper的client和server的實現類都會驗證znode存儲的數據是否小於1M,但是數據應該比平均值小的多。操作大數據將會觸發一些消耗時間的額外操作並且影響潛在的操作,因為需要額外的時間在網絡和存儲介質上轉移數據。如果有大數據需要存儲,通常的辦法是把這些數據存儲在專門的大型文件系統上,例如NFS或者HDFS,然后把存儲介質的位置存在zookeeper上。

 

Ephemeral Nodes

zookeeper有一種znode是ephemeral nodes。這些znode只在session存在期間有效。當session結束的時候這些ephemeral nodes被刪除。所以ephemeral znodes不能有子節點。

 

Sequence Nodes -- Unique Naming

當創建一個znode時候,你也可以要求zookeeper在path的結尾單調遞增。計數器對每一個znode來說都是唯一的。計數器使用%010d格式化--例如<path>0000000001。注意:計數器使用一個singed int(4bytes)來存儲下一個序列值。所以計數器達到2147483647 后會溢出。

 

zookeeper的每個節點可以有如下三種角色:

1.leader和follower

 

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

此操作實現的核心思想是:首先創建一個EPHEMERAL目錄節點,例如“/election”。然后。每一個ZooKeeper服務器在此目錄下創建一個SEQUENCE|EPHEMERAL類型的節點,例如“/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的操作。

 

 

2.Observer

      observer的行為在大多數情況下與follower完全一致, 但是他們不參加選舉和投票, 而僅僅接受(observing)選舉和投票的結果.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM