分布式服務(wù)框架Zookeeper介紹、原理及應(yīng)用

Zookeeper簡介

Zookeeper 分布式服務(wù)框架是 Apache Hadoop 的一個子項(xiàng)目,它主要是用來解決分布式應(yīng)用中經(jīng)常遇到的一些數(shù)據(jù)管理問題,如:統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式應(yīng)用配置項(xiàng)的管理等等。

Zookeeper基本概念

zk角色

Zookeeper中的角色主要有以下三類,如下表所示:


zookeeper角色

zk service網(wǎng)絡(luò)結(jié)構(gòu)

Zookeeper的工作集群可以簡單分成兩類,一個是Leader,唯一一個,其余的都是follower,如何確定Leader是通過內(nèi)部選舉確定的。


zookeeper服務(wù)
  1. Leader和各個follower是互相通信的,對于zk系統(tǒng)的數(shù)據(jù)都是保存在內(nèi)存里面的,同樣也會備份一份在磁盤上。
      對于每個zk節(jié)點(diǎn)而言,可以看做每個zk節(jié)點(diǎn)的命名空間是一樣的,也就是有同樣的數(shù)據(jù)。(可查看下面的樹結(jié)構(gòu))
  • 如果Leader掛了,zk集群會重新選舉,在毫秒級別就會重新選舉出一個Leaer。
  • 集群中除非有一半以上的zk節(jié)點(diǎn)掛了,zk service才不可用。

zk命名空間結(jié)構(gòu)

Zookeeper的命名空間就是zk應(yīng)用的文件系統(tǒng),它和linux的文件系統(tǒng)很像,也是樹狀,這樣就可以確定每個路徑都是唯一的,對于命名空間的操作必須都是絕對路徑操作。與linux文件系統(tǒng)不同的是,linux文件系統(tǒng)有目錄和文件的區(qū)別,而zk統(tǒng)一叫做znode,一個znode節(jié)點(diǎn)可以包含子znode,同時也可以包含數(shù)據(jù)。


zookeeper樹結(jié)構(gòu)

提示:
比如/Nginx/conf,/是一個znode,/Nginx是/的子znode,/Nginx還可以包含數(shù)據(jù),數(shù)據(jù)內(nèi)容就是所有安裝Nginx的機(jī)器IP,/Nginx/conf是/Nginx子znode,它也可以包含內(nèi)容,數(shù)據(jù)就是Nginx的配置文件內(nèi)容。在應(yīng)用中,我們可以通過這樣一個路徑就可以獲得所有安裝Nginx的機(jī)器IP列表,還可以獲得這些機(jī)器上Nginx的配置文件。

zk讀寫數(shù)據(jù)

zookeeper讀寫數(shù)據(jù)
  • 寫數(shù)據(jù),但一個客戶端進(jìn)行寫數(shù)據(jù)請求時,會指定zk集群中節(jié)點(diǎn),如果是follower接收到寫請求,就會把請求轉(zhuǎn)發(fā)給Leader,Leader通過內(nèi)部的Zab協(xié)議進(jìn)行原子廣播,直到所有zk節(jié)點(diǎn)都成功寫了數(shù)據(jù)后(內(nèi)存同步以及磁盤更新),這次寫請求算是完成,然后zk service就會給client發(fā)回響應(yīng)
  • 讀數(shù)據(jù),因?yàn)榧褐兴械膠k節(jié)點(diǎn)都呈現(xiàn)一個同樣的命名空間視圖(就是結(jié)構(gòu)數(shù)據(jù)),上面的寫請求已經(jīng)保證了寫一次數(shù)據(jù)必須保證集群所有的zk節(jié)點(diǎn)都是同步命名空間的,所以讀的時候可以在任意一臺zk節(jié)點(diǎn)上

ps:其實(shí)寫數(shù)據(jù)的時候不是要保證所有zk節(jié)點(diǎn)都寫完才響應(yīng),而是保證一半以上的節(jié)點(diǎn)寫完了就把這次變更更新到內(nèi)存,并且當(dāng)做最新命名空間的應(yīng)用。所以在讀數(shù)據(jù)的時候可能會讀到不是最新的zk節(jié)點(diǎn),這時候只能通過sync()解決。這里先不考慮了,假設(shè)整個zk service都是同步meta信息的,后面的文章再討論。

zk znode類型

Zookeeper中znode的節(jié)點(diǎn)創(chuàng)建時候是可以指定類型的,主要有下面幾種類型。

  1. PERSISTENT:持久化znode節(jié)點(diǎn),一旦創(chuàng)建這個znode點(diǎn)存儲的數(shù)據(jù)不會主動消失,除非是客戶端主動的delete。
    SEQUENCE:順序增加編號znode節(jié)點(diǎn),比如ClientA去zk service上建立一個znode名字叫做/Nginx/conf,指定了這種類型的節(jié)點(diǎn)后zk會創(chuàng)建/Nginx/conf0000000000,ClientB再去創(chuàng)建就是創(chuàng)建/Nginx/conf0000000001,ClientC是創(chuàng)建/Nginx/conf0000000002,以后任意Client來創(chuàng)建這個znode都會得到一個比當(dāng)前zk命名空間最大znode編號+1的znode,也就說任意一個Client去創(chuàng)建znode都是保證得到的znode是遞增的,而且是唯一的。
  • EPHEMERAL:臨時znode節(jié)點(diǎn),Client連接到zk service的時候會建立一個session,之后用這個zk連接實(shí)例創(chuàng)建該類型的znode,一旦Client關(guān)閉了zk的連接,服務(wù)器就會清除session,然后這個session建立的znode節(jié)點(diǎn)都會從命名空間消失??偨Y(jié)就是,這個類型的znode的生命周期是和Client建立的連接一樣的。比如ClientA創(chuàng)建了一個EPHEMERAL的/Nginx/conf0000000011的znode節(jié)點(diǎn),一旦ClientA的zk連接關(guān)閉,這個znode節(jié)點(diǎn)就會消失。整個zk service命名空間里就會刪除這個znode節(jié)點(diǎn)。
  • PERSISTENT|SEQUENTIAL:順序自動編號的znode節(jié)點(diǎn),這種znoe節(jié)點(diǎn)會根據(jù)當(dāng)前已近存在的znode節(jié)點(diǎn)編號自動加 1,而且不會隨session斷開而消失。
  • EPHEMERAL|SEQUENTIAL:臨時自動編號節(jié)點(diǎn),znode節(jié)點(diǎn)編號會自動增加,但是會隨session消失而消失

Zookeeper設(shè)計(jì)目的

  1. 最終一致性:client不論連接到哪個Server,展示給它都是同一個視圖,這是zookeeper最重要的性能。
  • 可靠性:具有簡單、健壯、良好的性能,如果消息m被到一臺服務(wù)器接受,那么它將被所有的服務(wù)器接受。
  • 實(shí)時性:Zookeeper保證客戶端將在一個時間間隔范圍內(nèi)獲得服務(wù)器的更新信息,或者服務(wù)器失效的信息。但由于網(wǎng)絡(luò)延時等原因,Zookeeper不能保證兩個客戶端能同時得到剛更新的數(shù)據(jù),如果需要最新數(shù)據(jù),應(yīng)該在讀數(shù)據(jù)之前調(diào)用sync()接口。
  • 等待無關(guān)(wait-free):慢的或者失效的client不得干預(yù)快速的client的請求,使得每個client都能有效的等待。
  • 原子性:更新只能成功或者失敗,沒有中間狀態(tài)。
  • 順序性:包括全局有序和偏序兩種:全局有序是指如果在一臺服務(wù)器上消息a在消息b前發(fā)布,則在所有Server上消息a都將在消息b前被發(fā)布;偏序是指如果一個消息b在消息a后被同一個發(fā)送者發(fā)布,a必將排在b前面。

Zookeeper工作原理

Zookeeper 的核心是廣播,這個機(jī)制保證了各個Server之間的同步。實(shí)現(xiàn)這個機(jī)制的協(xié)議叫做Zab協(xié)議。
  Zab協(xié)議有兩種模式,它們分別是恢復(fù)模式(選主)和廣播 模式(同步)。當(dāng)服務(wù)啟動或者在領(lǐng)導(dǎo)者崩潰后,Zab就進(jìn)入了恢復(fù)模式,當(dāng)領(lǐng)導(dǎo)者被選舉出來,且大多數(shù)Server完成了和leader的狀態(tài)同步以后, 恢復(fù)模式就結(jié)束了。狀態(tài)同步保證了leader和Server具有相同的系統(tǒng)狀態(tài)。為了保證事務(wù)的順序一致性,zookeeper采用了遞增的事務(wù)id號 (zxid)來標(biāo)識事務(wù)。所有的提議(proposal)都在被提出的時候加上了zxid。實(shí)現(xiàn)中zxid是一個64位的數(shù)字,它高32位是epoch用 來標(biāo)識leader關(guān)系是否改變,每次一個leader被選出來,它都會有一個新的epoch,標(biāo)識當(dāng)前屬于那個leader的統(tǒng)治時期。低32位用于遞增計(jì)數(shù)。

每個Server在工作過程中有三種狀態(tài):

  • LOOKING:當(dāng)前Server不知道leader是誰,正在搜尋。
  • LEADING:當(dāng)前Server即為選舉出來的leader。
  • FOLLOWING:leader已經(jīng)選舉出來,當(dāng)前Server與之同步。

選主流程

當(dāng) leader崩潰或者leader失去大多數(shù)的follower,這時候zk進(jìn)入恢復(fù)模式,恢復(fù)模式需要重新選舉出一個新的leader,讓所有的 Server都恢復(fù)到一個正確的狀態(tài)。
Zookeeper的選舉算法有兩種:
  一種是基于basic paxos實(shí)現(xiàn)的,另外一種是基于fast paxos算法實(shí)現(xiàn)的。
系統(tǒng)默認(rèn)的選舉算法為fast paxos。
basic paxos流程:

  1. 選舉線程由當(dāng)前Server發(fā)起選舉的線程擔(dān)任,其主要功能是對投票結(jié)果進(jìn)行統(tǒng)計(jì),并選出推薦的Server;
  • 選舉線程首先向所有Server發(fā)起一次詢問(包括自己);
  • 選舉線程收到回復(fù)后,驗(yàn)證是否是自己發(fā)起的詢問(驗(yàn)證zxid是否一致),然后獲取對方的id(myid),并存儲到當(dāng)前詢問對象列表中,最后獲取對方提議的leader相關(guān)信息(id,zxid),并將這些信息存儲到當(dāng)次選舉的投票記錄表中;
  • 收到所有Server回復(fù)以后,就計(jì)算出zxid最大的那個Server,并將這個Server相關(guān)信息設(shè)置成下一次要投票的Server;
  • 線程將當(dāng)前zxid最大的Server設(shè)置為當(dāng)前Server要推薦的Leader,如果此時獲勝的Server獲得n/2 + 1的Server票數(shù), 設(shè)置當(dāng)前推薦的leader為獲勝的Server,將根據(jù)獲勝的Server相關(guān)信息設(shè)置自己的狀態(tài),否則,繼續(xù)這個過程,直到leader被選舉出來。通 過流程分析我們可以得出:要使Leader獲得多數(shù)Server的支持,則Server總數(shù)必須是奇數(shù)2n+1,且存活的Server的數(shù)目不得少于 n+1.每個Server啟動后都會重復(fù)以上流程。在恢復(fù)模式下,如果是剛從崩潰狀態(tài)恢復(fù)的或者剛啟動的server還會從磁盤快照中恢復(fù)數(shù)據(jù)和會話信 息,zk會記錄事務(wù)日志并定期進(jìn)行快照,方便在恢復(fù)時進(jìn)行狀態(tài)恢復(fù)。
    選舉的具體流程圖如下所示:

zk basic paxos選舉

fast paxos流程:
  在選舉過程中,某Server首先向所有Server提議自己要成為leader,當(dāng)其它Server收到提議以后,解決epoch和 zxid的沖突,并接受對方的提議,然后向?qū)Ψ桨l(fā)送接受提議完成的消息,重復(fù)這個流程,最后一定能選舉出Leader。
選舉的具體流程圖如下所示:

zk fast paxos選舉

同步流程

選完leader以后,zk就進(jìn)入狀態(tài)同步過程。

  1. leader等待server連接;
  • Follower連接leader,將最大的zxid發(fā)送給leader;
  • Leader根據(jù)follower的zxid確定同步點(diǎn);
  • 完成同步后通知follower 已經(jīng)成為uptodate狀態(tài);
  • Follower收到uptodate消息后,又可以重新接受client的請求進(jìn)行服務(wù)了。
    同步的具體流程圖如下所示:
zk同步流程

工作流程

Leader工作流程

  1. 恢復(fù)數(shù)據(jù);
  • 維持與Learner的心跳,接收Learner請求并判斷Learner的請求消息類型;
  • Learner的消息類型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根據(jù)不同的消息類型,進(jìn)行不同的處理。

PING 消息是指Learner的心跳信息;
REQUEST消息是Follower發(fā)送的提議信息,包括寫請求及同步請求;
ACK消息是Follower的對提議 的回復(fù),超過半數(shù)的Follower通過,則commit該提議;
REVALIDATE消息是用來延長SESSION有效時間。

Leader的工作流程簡圖具體如下所示:

Leader工作流程

Follower工作流程

Follower主要有四個功能:

  1. 向Leader發(fā)送請求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);
  • 接收Leader消息并進(jìn)行處理;
  • 接收Client的請求,如果為寫請求,發(fā)送給Leader進(jìn)行投票;
  • 返回Client結(jié)果。
    Follower的消息循環(huán)處理如下幾種來自Leader的消息:
  1. PING消息: 心跳消息;
  • PROPOSAL消息:Leader發(fā)起的提案,要求Follower投票;
  • COMMIT消息:服務(wù)器端最新一次提案的信息;
  • UPTODATE消息:表明同步完成;
  • REVALIDATE消息:根據(jù)Leader的REVALIDATE結(jié)果,關(guān)閉待revalidate的session還是允許其接受消息;
  • SYNC消息:返回SYNC結(jié)果到客戶端,這個消息最初由客戶端發(fā)起,用來強(qiáng)制得到最新的更新。
    Follower的工作流程簡圖具體如下所示:
Follower的工作流程

應(yīng)用篇

分布式系統(tǒng)的運(yùn)行是很復(fù)雜的,因?yàn)樯婕暗搅司W(wǎng)絡(luò)通信還有節(jié)點(diǎn)失效等不可控的情況。下面介紹在最傳統(tǒng)的master-workers模型,主要可以會遇到什么問題,傳統(tǒng)方法是怎么解決以及怎么用zookeeper解決。

Master節(jié)點(diǎn)管理

集群當(dāng)中最重要的是Master,所以一般都會設(shè)置一臺Master的Backup。
Backup會定期向Master獲取Meta信息并且檢測Master的存活性,一旦Master掛了,Backup立馬啟動,接替Master的工作自己成為Master,分布式的情況多種多樣,因?yàn)樯婕暗搅司W(wǎng)絡(luò)通信的抖動,針對下面的情況:

  1. Backup檢測Master存活性傳統(tǒng)的就是定期發(fā)包,一旦一定時間段內(nèi)沒有收到響應(yīng)就判定Master Down了,于是Backup就啟動,如果Master其實(shí)是沒有down,Backup收不到響應(yīng)或者收到響應(yīng)延遲的原因是因?yàn)榫W(wǎng)絡(luò)阻塞的問題呢?Backup也啟動了,這時候集群里就有了兩個Master,很有可能部分workers匯報給Master,另一部分workers匯報給后來啟動的Backup,這下子服務(wù)就全亂了。
  • Backup是定期同步Master中的meta信息,所以總是滯后的,一旦Master掛了,Backup的信息必然是老的,很有可能會影響集群運(yùn)行狀態(tài)。
    解決問題:
    Master節(jié)點(diǎn)高可用,并且保證唯一。
    Meta信息的及時同步。
    ** Zookeeper Master選舉 **
      Zookeeper會分配給注冊到它上面的客戶端一個編號,并且zk自己會保證這個編號的唯一性和遞增性,N多機(jī)器中只需選出編號最小的Client作為Master就行,并且保證這些機(jī)器的都維護(hù)一個一樣的meta信息視圖,一旦Master掛了,那么這N機(jī)器中編號最小的勝任Master,Meta信息是一致的。

集群worker管理

集群中的worker掛了是很可能的,一旦worker A掛了,如果存在其余的workers互相之間需要通信,那么workers必須盡快更新自己的hosts列表,把掛了的worker剔除,從而不在和它通信,而Master要做的是把掛了worker上的作業(yè)調(diào)度到其他的worker上。同樣的,這臺worker重新恢復(fù)正常了,要通知其他的workers更新hosts列表。傳統(tǒng)的作法都是有專門的監(jiān)控系統(tǒng),通過不斷去發(fā)心跳包(比如ping)來發(fā)現(xiàn)worker是否alive,缺陷就是及時性問題,不能應(yīng)用于在線率要求較高的場景
解決問題:
集群worker監(jiān)控。
** Zookeeper監(jiān)控集群 **
  利用zookeeper建立znode的強(qiáng)一致性,可以用于那種對集群中機(jī)器狀態(tài),機(jī)器在線率有較高要求的場景,能夠快速對集群中機(jī)器變化作出響應(yīng)。

分布式鎖

在一臺機(jī)器上要多個進(jìn)程或者多個線程操作同一資源比較簡單,因?yàn)榭梢杂写罅康臓顟B(tài)信息或者日志信息提供保證,比如兩個A和B進(jìn)程同時寫一個文件,加鎖就可以實(shí)現(xiàn)。但是分布式系統(tǒng)怎么辦?需要一個三方的分配鎖的機(jī)制,幾百臺worker都對同一個網(wǎng)絡(luò)中的文件寫操作,怎么協(xié)同?還有怎么保證高效的運(yùn)行?
解決問題:
高效分布式的分布式鎖
Zookeeper分布式鎖
  分布式鎖主要得益于ZooKeeper為我們保證了數(shù)據(jù)的強(qiáng)一致性,zookeeper的znode節(jié)點(diǎn)創(chuàng)建的唯一性和遞增性能保證所有來搶鎖的worker的原子性。

配置文件管理

集群中配置文件的更新和同步是很頻繁的,傳統(tǒng)的配置文件分發(fā)都是需要把配置文件數(shù)據(jù)分發(fā)到每臺worker上,然后進(jìn)行worker的reload,這種方式是最笨的方式,結(jié)構(gòu)很難維護(hù),因?yàn)槿绻寒?dāng)中有可能很多種應(yīng)用的配置文件要同步,而且效率很低,集群規(guī)模一大負(fù)載很高。還有一種就是每次更新把配置文件單獨(dú)保存到一個數(shù)據(jù)庫里面,然后worker端定期pull數(shù)據(jù),這種方式就是數(shù)據(jù)及時性得不到同步。
解決問題:
統(tǒng)一配置文件分發(fā)并且及時讓worker生效
Zookeeper發(fā)布與訂閱模型
  發(fā)布與訂閱模型,即所謂的配置中心,顧名思義就是發(fā)布者將數(shù)據(jù)發(fā)布到ZK節(jié)點(diǎn)上,供訂閱者動態(tài)獲取數(shù)據(jù),實(shí)現(xiàn)配置信息的集中式管理和動態(tài)更新。例如全局的配置信息,服務(wù)式服務(wù)框架的服務(wù)地址列表等就非常適合使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容