溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Zookeeper的核心原理是什么

發(fā)布時間:2021-07-05 16:40:57 來源:億速云 閱讀:153 作者:chen 欄目:web開發(fā)

這篇文章主要介紹“Zookeeper的核心原理是什么”,在日常操作中,相信很多人在Zookeeper的核心原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Zookeeper的核心原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

之前的文章Zookeeper基礎原理&應用場景詳解中將Zookeeper的基本原理及其應用場景做了一個詳細的介紹,雖然介紹了其底層的存儲原理、如何使用Zookeeper來實現(xiàn)分布式鎖。但是我認為這樣也僅僅只是了解了Zookeeper的一點皮毛而已。所以這篇文章就給大家詳細聊聊Zookeeper的核心底層原理。不太熟悉Zookeeper的可以回過頭去看看。

ZNode

這個應該算是Zookeeper中的基礎,數(shù)據(jù)存儲的最小單元。在Zookeeper中,類似文件系統(tǒng)的存儲結(jié)構(gòu),被Zookeeper抽象成了樹,樹中的每一個節(jié)點(Node)被叫做ZNode。ZNode中維護了一個數(shù)據(jù)結(jié)構(gòu),用于記錄ZNode中數(shù)據(jù)更改的版本號以及ACL(Access  Control List)的變更。

有了這些數(shù)據(jù)的版本號以及其更新的Timestamp,Zookeeper就可以驗證客戶端請求的緩存是否合法,并協(xié)調(diào)更新。

而且,當Zookeeper的客戶端執(zhí)行更新或者刪除操作時,都必須要帶上要修改的對應數(shù)據(jù)的版本號。如果Zookeeper檢測到對應的版本號不存在,則不會執(zhí)行這次更新。如果合法,在ZNode中數(shù)據(jù)更新之后,其對應的版本號也會一起更新。

  • 這套版本號的邏輯,其實很多框架都在用,例如RocketMQ中,Broker向NameServer注冊的時候,也會帶上這樣一個版本號,叫DateVersion。

接下來我們來詳細看一下這個維護版本號相關(guān)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),它叫Stat Structure,其字段有:

Zookeeper的核心原理是什么

舉個例子,通過stat命令,我們可以查看某個ZNode中Stat Structure具體的值。

Zookeeper的核心原理是什么

關(guān)于這里的epoch、zxid是Zookeeper集群相關(guān)的東西,后面會詳細的對其進行介紹。

ACL

ACL(Access Control  List)用于控制ZNode的相關(guān)權(quán)限,其權(quán)限控制和Linux中的類似。Linux中權(quán)限種類分為了三種,分別是讀、寫、執(zhí)行,分別對應的字母是r、w、x。其權(quán)限粒度也分為三種,分別是擁有者權(quán)限、群組權(quán)限、其他組權(quán)限,舉個例子:

drwxr-xr-x  3 USERNAME  GROUP  1.0K  3 15 18:19 dir_name

什么叫粒度?粒度是對權(quán)限所作用的對象的分類,把上面三種粒度換個說法描述就是**對用戶(Owner)、用戶所屬的組(Group)、其他組(Other)**的權(quán)限劃分,這應該算是一種權(quán)限控制的標準了,典型的三段式。

Zookeeper中雖然也是三段式,但是兩者對粒度的劃分存在區(qū)別。Zookeeper中的三段式為Scheme、ID、Permissions,含義分別為權(quán)限機制、允許訪問的用戶和具體的權(quán)限。

Zookeeper的核心原理是什么

Scheme代表了一種權(quán)限模式,有以下5種類型:

  • world 在此中Scheme下,ID只能是anyone,代表所有人都可以訪問

  • auth 代表已經(jīng)通過了認證的用戶

  • digest 使用用戶名+密碼來做校驗。

  • ip 只允許某些特定的IP訪問ZNode

  • X509 通過客戶端的證書進行認證

同時權(quán)限種類也有五種:

  • CREATE 創(chuàng)建節(jié)點

  • READ 獲取節(jié)點或列出其子節(jié)點

  • WRITE 能設置節(jié)點的數(shù)據(jù)

  • DELETE 能夠刪除子節(jié)點

  • ADMIN 能夠設置權(quán)限

同Linux中一樣,這個權(quán)限也有縮寫,舉個例子:

Zookeeper的核心原理是什么

getAcl方法用戶查看對應的ZNode的權(quán)限,如圖,我們可以輸出的結(jié)果呈三段式。分別是:

  • scheme 使用了world

  • id 值為anyone,代表所有用戶都有權(quán)限

  • permissions 其具體的權(quán)限為cdrwa,分別是CREATE、DELETE、READ、WRITE和ADMIN的縮寫

Session機制

了解了Zookeeper的Version機制,我們可以繼續(xù)探索Zookeeper的Session機制了。

我們知道,Zookeeper中有4種類型的節(jié)點,分別是持久節(jié)點、持久順序節(jié)點、臨時節(jié)點和臨時順序節(jié)點。

在之前的文章我們聊到過,客戶端如果創(chuàng)建了臨時節(jié)點,并在之后斷開了連接,那么所有的臨時節(jié)點就都會被刪除。實際上斷開連接的說話不是很精確,應該是說客戶端建立連接時的Session過期之后,其創(chuàng)建的所有臨時節(jié)點就會被全部刪除。

那么Zookeeper是怎么知道哪些臨時節(jié)點是由當前客戶端創(chuàng)建的呢?

  • 答案是Stat Structure中的**ephemeralOwner(臨時節(jié)點的Owner)**字段

上面說過,如果當前是臨時順序節(jié)點,那么ephemeralOwner則存儲了創(chuàng)建該節(jié)點的Owner的SessionID,有了SessionID,自然就能和對應的客戶端匹配上,當Session失效之后,才能將該客戶端創(chuàng)建的所有臨時節(jié)點全部刪除。

Zookeeper的核心原理是什么

對應的服務在創(chuàng)建連接的時候,必須要提供一個帶有所有服務器、端口的字符串,單個之間逗號相隔,舉個例子。

  • 127.0.0.1:3000:2181,127.0.0.1:2888,127.0.0.1:3888

Zookeeper的客戶端收到這個字符串之后,會從中隨機選一個服務、端口來建立連接。如果連接在之后斷開,客戶端會從字符串中選擇下一個服務器,繼續(xù)嘗試連接,直到連接成功。

除了這種最基本的IP+端口,在Zookeeper的3.2.0之后的版本中還支持連接串中帶上路徑,舉個例子。

  • 127.0.0.1:3000:2181,127.0.0.1:2888,127.0.0.1:3888/app/a

這樣一來,/app/a就會被當成當前服務的根目錄,在其下創(chuàng)建的所有的節(jié)點路經(jīng)都會帶上前綴/app/a。舉個例子,我創(chuàng)建了一個節(jié)點/node_name,那其完整的路徑就會為/app/a/node_name。這個特性特別適用于多租戶的環(huán)境,對于每個租戶來說,都認為自己是最頂層的根目錄/。

當Zookeeper的客戶端和服務器都建立了連接之后,客戶端會拿到一個64位的SessionID和密碼。這個密碼是干什么用的呢?我們知道Zookeeper可以部署多個實例,如果客戶端斷開了連接又和另外的Zookeeper服務器建立了連接,那么在建立連接使就會帶上這個密碼。該密碼是Zookeeper的一種安全措施,所有的Zookeeper節(jié)點都可以對其進行驗證。這樣一來,即使連接到了其他Zookeeper節(jié)點,Session同樣有效。

Session過期有兩種情況,分別是:

  • 過了指定的失效時間

  • 指定時間內(nèi)客戶端沒有發(fā)送心跳

對于第一種情況,過期時間會在Zookeeper客戶端建立連接的時候傳給服務器,這個過期時間的范圍目前只能在2倍tickTime和20倍tickTime之間。

ticktime是Zookeeper服務器的配置項,用于指定客戶端向服務器發(fā)送心跳的間隔,其默認值為tickTime=2000,單位為毫秒

而這套Session的過期邏輯由Zookeeper的服務器維護,一旦Session過期,服務器會立即刪除由Client創(chuàng)建的所有臨時節(jié)點,然后通知所有正在監(jiān)聽這些節(jié)點的客戶端相關(guān)變更。

對于第二種情況,Zookeeper中的心跳是通過PING請求來實現(xiàn)的,每隔一段時間,客戶端都會發(fā)送PING請求到服務器,這就是心跳的本質(zhì)。心跳使服務器感知到客戶端還活著,同樣的讓客戶端也感知到和服務器的連接仍然是有效的,這個間隔就是**tickTime**,默認為2秒。

Watch機制

了解完ZNode和Session,我們終于可以來繼續(xù)下一個關(guān)鍵功能Watch了,在上面的內(nèi)容中也不止一次的提到**監(jiān)聽(Watch)**這個詞。首先用一句話來概括其作用

  • 給某個節(jié)點注冊監(jiān)聽器,該節(jié)點一旦發(fā)生變更(例如更新或者刪除),監(jiān)聽者就會收到一個Watch Event

和ZNode中有多種類型一樣,Watch也有多種類型,分別是一次性Watch和永久性Watch。

  • 一次性Watch 在被觸發(fā)之后,該Watch就會移除

  • 永久性Watch 在被觸發(fā)之后,仍然保留,可以繼續(xù)監(jiān)聽ZNode上的變更,是Zookeeper 3.6.0版本新增的功能

一次性的Watch可以在調(diào)用getData()、getChildren()和exists()等方法時在參數(shù)中進行設置,永久性的Watch則需要調(diào)用addWatch()來實現(xiàn)。

并且一次性的Watch會存在問題,因為在Watch觸發(fā)的事件到達客戶端、再到客戶端設立新的Watch,是有一個時間間隔的。而如果在這個時間間隔中發(fā)生的變更,客戶端則無法感知。

Zookeeper的核心原理是什么

Zookeeper集群架構(gòu)

ZAB協(xié)議

把前面的都鋪墊好之后就可以來從整體架構(gòu)的角度再深入了解Zookeeper。Zookeeper為了保證其高可用,采用的基于主從的讀寫分離架構(gòu)。

  • 我們知道在類似的Redis主從架構(gòu)中,節(jié)點之間是采用的Gossip協(xié)議來進行通信的,那么在Zookeeper中通信協(xié)議是什么?

答案是**ZAB(Zookeeper Atomic Broadcast)**協(xié)議。

ZAB協(xié)議是一種支持崩潰恢復的的原子廣播協(xié)議,用于在Zookeeper之間傳遞消息,使所有的節(jié)點都保持同步。ZAB同時具有高性能、高可用的、容易上手、利于維護的特點,同時支持自動的故障恢復。

ZAB協(xié)議將Zookeeper集群中的節(jié)點劃分成了三個角色,分別是Leader、Follower和Observer,如下圖:

Zookeeper的核心原理是什么

總的來說,這套架構(gòu)和Redis主從或者MySQL主從的架構(gòu)類似(感興趣的也可以去看之前的寫的文章,都有聊過)

  • Redis主從

  • MySQL主從

不同點在于,通常的主從架構(gòu)中存在兩種角色,分別是Leader、Follower(或者是Master、Slave),但Zookeeper中多了一個Observer。

  • 那問題來了,Observer和Follower的區(qū)別是啥呢?

本質(zhì)上來說兩者的功能是一樣的,  都為Zookeeper提供了橫向擴展的能力,使其能夠扛住更多的并發(fā)。但區(qū)別在于Leader的選舉過程中,Observer不參與投票選舉。

順序一致性

上文提到了Zookeeper集群中是讀寫分離的,只有Leader節(jié)點能處理寫請求,如果Follower節(jié)點接收到了寫請求,會將該請求轉(zhuǎn)發(fā)給Leader節(jié)點處理,F(xiàn)ollower節(jié)點自身是不會處理寫請求的。

Leader節(jié)點接收到消息之后,會按照請求的嚴格順序一一的進行處理。這是Zookeeper的一大特點,它會保證消息的順序一致性。

  • 舉個例子,如果消息A比消息B先到,那么在所有的Zookeeper節(jié)點中,消息A都會先于消息B到達,Zookeeper會保證消息的全局順序。

zxid

那Zookeeper是如何保證消息的順序?答案是通過zxid。

可以簡單的把zxid理解成Zookeeper中消息的唯一ID,節(jié)點之間會通過發(fā)送**Proposal(事務提議)**來進行通信、數(shù)據(jù)同步,proposal中就會帶上zxid和具體的數(shù)據(jù)(Message)。而zxid由兩部分組成:

Zookeeper的核心原理是什么

  • epoch 可以理解成朝代,或者說Leader迭代的版本,每個Leader的epoch都不一樣

  • counter 計數(shù)器,來一條消息就會自增

這也是唯一zxid生成算法的底層實現(xiàn),由于每個Leader所使用的epoch都是唯一的,而不同的消息在相同的epoch中,counter的值是不同的,這樣一來所有的proposal在Zookeeper集群中都有唯一的zxid。

恢復模式

正常運行的Zookeeper集群會處于廣播模式。相反,如果超過半數(shù)的節(jié)點宕機,就會進入恢復模式。

  • 什么是恢復模式?

在Zookeeper集群中,存在兩種模式,分別是:

  • 恢復模式

  • 廣播模式

當Zookeeper集群故障時會進入恢復模式,也叫做Leader  Activation,顧名思義就是要在此階段選舉出Leader。節(jié)點之間會生成zxid和Proposal,然后相互投票。投票是要有原則的,主要有兩條:

  • 選舉出來的Leader的zxid一定要是所有的Follower中最大的

  • 并且已有超過半數(shù)的Follower返回了ACK,表示認可選舉出來的Leader

如果在選舉的過程中發(fā)生異常,Zookeeper會直接進行新一輪的選舉。如果一切順利,Leader就會被成功選舉出來,但是此時集群還不能正常對外提供服務,因為新的Leader和Follower之間還沒有進行關(guān)鍵的數(shù)據(jù)同步。

此后,Leader會等待其余的Follower來連接,然后通過Proposal向所有的Follower發(fā)送其缺失的數(shù)據(jù)。

  • 至于怎么知道缺失哪些數(shù)據(jù),Proposal本身是要記錄日志,通過Proposal中的zxid的低32位的Counter中的值,就可以做一個Diff

當然這里有個優(yōu)化,如果缺失的數(shù)據(jù)太多,那么一條一條的發(fā)送Proposal效率太低。所以如果Leader發(fā)現(xiàn)缺失的數(shù)據(jù)過多就會將當前的數(shù)據(jù)打個快照,直接打包發(fā)送給Follower。

新選舉出來的Leader的Epoch,會在原來的值上+1,并且將Counter重置為0。

  • 到這你是不是以為就完了?實際上到這還是無法正常提供服務

數(shù)據(jù)同步完成之后,Leader會發(fā)送一個NEW_LEADER的Proposal給Follower,當且僅當該Proposal被過半的Follower返回Ack之后,Leader才會Commit該NEW_LEADER  Proposal,集群才能正常的進行工作。

至此,恢復模式結(jié)束,集群進入廣播模式。

廣播模式

在廣播模式下,Leader接收到消息之后,會向其他所有Follower發(fā)送Proposal(事務提議),F(xiàn)ollower接收到Proposal之后會返回ACK給Leader。當Leader收到了quorums個ACK之后,當前Proposal就會提交,被應用到節(jié)點的內(nèi)存中去。quorum個是多少呢?

Zookeeper官方建議每2個Zookeeper節(jié)點中,至少有一個需要返回ACK才行,假設有N個Zookeeper節(jié)點,那計算公式應該是n/2 +  1。

這樣可能不是很直觀,用大白話來說就是,超過半數(shù)的Follower返回了ACK,該Proposal就能夠提交,并且應用至內(nèi)存中的ZNode。

Zookeeper的核心原理是什么

Zookeeper使用2PC來保證節(jié)點之間的數(shù)據(jù)一致性(如上圖),但是由于Leader需要跟所有的Follower交互,這樣一來通信的開銷會變得較大,Zookeeper的性能就會下降。所以為了提升Zookeeper的性能,才從所有的Follower節(jié)點返回ACK變成了過半的Follower返回ACK即可。

到此,關(guān)于“Zookeeper的核心原理是什么”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI