首先認(rèn)識ZooKeeper
ZooKeeper—譯名為“動(dòng)物園管理員”。動(dòng)物園里當(dāng)然有好多的動(dòng)物,游客可以根據(jù)動(dòng)物園提供的向?qū)D到不同的場館觀賞各種類型的動(dòng)物,而不是像走在原始叢林里,心驚膽顫的被動(dòng) 物所觀賞。為了讓各種不同的動(dòng)物呆在它們應(yīng)該呆的地方,而不是相互串門,或是相互廝殺,就需要?jiǎng)游飯@管理員按照動(dòng)物的各種習(xí)性加以分類和管理,這樣我們才能更加放心安全的觀賞動(dòng)物。
回到企業(yè)級應(yīng)用系統(tǒng)中,隨著信息化水平的不斷提高,企業(yè)級系統(tǒng)變得越來越龐大臃腫,性能急劇下降,客戶抱怨頻頻。拆分系統(tǒng)是目前我們可選擇的解決系統(tǒng)可伸縮性和性能問題的唯一行之有效的方法。但是拆分系統(tǒng)同時(shí)也帶來了系統(tǒng)的復(fù)雜性——各子系統(tǒng)不是孤立存在的,它們彼此之間需要協(xié)作和交互,這就是我們常說的分布式系統(tǒng)。各個(gè)子系統(tǒng)就好比動(dòng)物園里的動(dòng)物,為了使各個(gè)子系統(tǒng)能正常為用戶提供統(tǒng)一的服務(wù),必須需要一種機(jī)制來進(jìn)行協(xié)調(diào)——這就是ZooKeeper(動(dòng)物園管理員)。
為什么使用ZooKeeper
我們知道要寫一個(gè)分布式應(yīng)用是非常困難的,主要原因就是局部故障。一個(gè)消息通過網(wǎng)絡(luò)在兩個(gè)節(jié)點(diǎn)之間傳遞時(shí),網(wǎng)絡(luò)如果發(fā)生故障,發(fā)送方并不知道接收方是否接收到了這個(gè)消息。他可能在網(wǎng)絡(luò)故障遷就收到了此消息,也可能沒有收到,又或者可能接收方的進(jìn)程死了。發(fā)送方了解情況的唯一方法就是再次連接發(fā)送方,并向他進(jìn)行詢問。這就是局部故障:根本不知道操作是否失敗。因此,大部分分布式應(yīng)用需要一個(gè)主控、協(xié)調(diào)控制器來管理物理分布的子進(jìn)程。目前,大部分應(yīng)用需要開發(fā)私有的協(xié)調(diào)程序,缺乏一個(gè)通用的機(jī)制。協(xié)調(diào)程序的反復(fù)編寫浪費(fèi),且難以形成通用、伸縮性好的協(xié)調(diào)器。協(xié)調(diào)服務(wù)非常容易出錯(cuò),并很難從故障中恢復(fù)。例如:協(xié)調(diào)服務(wù)很容易處于競態(tài)1甚至死鎖2。Zookeeper的設(shè)計(jì)目的,是為了減輕分布式應(yīng)用程序所承擔(dān)的協(xié)調(diào)任務(wù)。
Zookeeper并不能阻止局部故障的發(fā)生,因?yàn)樗鼈兊谋举|(zhì)是分布式系統(tǒng)。他當(dāng)然也不會(huì)隱藏局部故障。ZooKeeper的目的就是提供一些工具集,用來建立安全處理局部故障的分布式應(yīng)用。
ZooKeeper是一個(gè)分布式小文件系統(tǒng),并且被設(shè)計(jì)為高可用性。通過選舉算法和集群復(fù)制可以避免單點(diǎn)故障,由于是文件系統(tǒng),所以即使所有的ZooKeeper節(jié)點(diǎn)全部掛掉,數(shù)據(jù)也不會(huì)丟失,重啟服務(wù)器之后,數(shù)據(jù)即可恢復(fù)。另外ZooKeeper的節(jié)點(diǎn)更新是原子的,也就是說更新不是成功就是失敗。通過版本號,ZooKeeper實(shí)現(xiàn)了更新的樂觀鎖,當(dāng)版本號不相符時(shí),則表示待更新的節(jié)點(diǎn)已經(jīng)被其他客戶端提前更新了,而當(dāng)前的整個(gè)更新操作將全部失敗。當(dāng)然所有的一切ZooKeeper已經(jīng)為開發(fā)者提供了保障,我們需要做的只是調(diào)用API。與此同時(shí),隨著分布式應(yīng)用的的不斷深入,需要對集群管理逐步透明化監(jiān)控集群和作業(yè)狀態(tài),可以充分利ZK的獨(dú)有特性。
ZooKeeper的應(yīng)用
ZooKeeper本質(zhì)上是一個(gè)分布式的小文件存儲系統(tǒng)。原本是Apache Hadoop的一個(gè)組件,現(xiàn)在被拆分為一個(gè)Hadoop的獨(dú)立子項(xiàng)目,在Hbase(Hadoop的另外一個(gè)被拆分出來的子項(xiàng)目,用于分布式環(huán)境下的超大數(shù)據(jù)量的DBMS)中也用到了ZooKeeper集群。
Hadoop,使用Zookeeper的事件處理確保整個(gè)集群只有一個(gè)NameNode,存儲配置信息等.HBase,使用Zookeeper的事件處理確保整個(gè)集群只有一個(gè)HMaster,察覺HRegionServer聯(lián)機(jī)和宕(dàng)機(jī),存儲訪問控制列表等。
有人會(huì)懷疑ZooKeeper的執(zhí)行能力,在ZooKeeper誕生的地方——Yahoo!他被用作雅虎消息代理的協(xié)調(diào)和故障恢復(fù)服務(wù)。雅虎消息代理是一個(gè)高度可擴(kuò)展的發(fā)布-訂閱系統(tǒng),他管理著成千上萬臺聯(lián)及程序和信息控制系統(tǒng)。它的吞吐量標(biāo)準(zhǔn)已經(jīng)達(dá)到大約每秒10000基于寫操作的工作量。對于讀操作的工作量來說,它的吞吐量標(biāo)準(zhǔn)還要高幾倍。
ZooKeeper的概述
Zookeeper 是為分布式應(yīng)用程序提供高性能協(xié)調(diào)服務(wù)的工具集合,也是Google的Chubby一個(gè)開源的實(shí)現(xiàn),是Hadoop 的分布式協(xié)調(diào)服務(wù)。它包含一個(gè)簡單的原語集,分布式應(yīng)用程序可以基于它實(shí)現(xiàn)配置維護(hù)、命名服務(wù)、分布式同步、組服務(wù)等。Zookeeper可以用來保證數(shù)據(jù)在ZK集群之間的數(shù)據(jù)的事務(wù)性一致。其中ZooKeeper提供通用的分布式鎖服務(wù),用以協(xié)調(diào)分布式應(yīng)用。
Zookeeper作為Hadoop項(xiàng)目中的一個(gè)子項(xiàng)目,是 Hadoop集群管理的一個(gè)必不可少的模塊,它主要用來解決分布式應(yīng)用中經(jīng)常遇到的數(shù)據(jù)管理問題,如集群管理、統(tǒng)一命名服務(wù)、分布式配置管理、分布式消息隊(duì)列、分布式鎖、分布式協(xié)調(diào)等。在Hadoop中,它管理Hadoop集群中的NameNode,還有在Hbase中Master Election、Server 之間狀態(tài)同狀步等。Zoopkeeper 提供了一套很好的分布式集群管理的機(jī)制,就是它這種基于層次型的目錄樹的數(shù)據(jù)結(jié)構(gòu),并對樹中的節(jié)點(diǎn)進(jìn)行有效管理,從而可以設(shè)計(jì)出多種多樣的分布式的數(shù)據(jù)管理模型。
Zookeeper是Apache Hadoop的一個(gè)子項(xiàng)目,主要是用來解決分布式應(yīng)用中經(jīng)常遇到的一些數(shù)據(jù)管理問題。下圖列舉了一些可能會(huì)遇到的場景:
ZooKeeper的設(shè)計(jì)目標(biāo)
眾所周知,分布式環(huán)境下的程序和活動(dòng)為了達(dá)到協(xié)調(diào)一致目的,通常具有某些共同的特點(diǎn),例如,簡單性、有序性等。ZooKeeper不但在這些目標(biāo)的實(shí)現(xiàn)上有自身特點(diǎn),并且具有獨(dú)特優(yōu)勢。高性能保證了ZooKeeper可以用于大型的分布式系統(tǒng),高可靠保證了ZooKeeper不會(huì)發(fā)生單點(diǎn)故障,嚴(yán)格的順序訪問保證了客戶端可以獲得復(fù)雜的同步操作原語。下面我們將簡述ZooKeeper的設(shè)計(jì)目標(biāo)。
(1)數(shù)據(jù)結(jié)構(gòu)簡單
ZooKeeper允許各分布式進(jìn)程通過一個(gè)共享的命名空間相互聯(lián)系,該命名空間類似于一個(gè)標(biāo)準(zhǔn)的層次型的文件系統(tǒng):由若干注冊了的數(shù)據(jù)節(jié)點(diǎn)構(gòu)成(用Zookeeper的術(shù)語叫znode),這些節(jié)點(diǎn)類似于文件和目錄。典型的文件系統(tǒng)是基于存儲設(shè)備的,傳統(tǒng)的文件系統(tǒng)主要用于存儲功能,然而ZooKepper的數(shù)據(jù)是保存在內(nèi)存中的。也就是說,可以獲得高吞吐和低延遲。ZooKeeper的實(shí)現(xiàn)非常重視高性能、高可靠,以及嚴(yán)格的有序訪問。
(2)高可靠(健壯性)
就像ZooKeeper需要協(xié)調(diào)的分布式系統(tǒng)一樣,它本身就是具有冗余結(jié)構(gòu),它構(gòu)建在一系列主機(jī)之上,叫做一個(gè)”ensemble”。構(gòu)成ZooKeeper服務(wù)的各服務(wù)器之間必須相互知道,它們維護(hù)著一個(gè)狀態(tài)信息的內(nèi)存映像,以及在持久化存儲中維護(hù)著事務(wù)日志和快照。只要大部分服務(wù)器正常工作,ZooKeeper服務(wù)就能正常工作。客戶端連接到一臺ZooKeeper服務(wù)器。客戶端維護(hù)這個(gè)TCP連接,通過這個(gè)連接,客戶端可以發(fā)送請求、得到應(yīng)答,得到監(jiān)視事件以及發(fā)送心跳。如果這個(gè)連接斷了,客戶端可以連接到另一個(gè)ZooKeeper服務(wù)器。
(3)有序性(嚴(yán)格的順序訪問)
ZooKeeper給每次更新附加一個(gè)數(shù)字標(biāo)簽,表明ZooKeeper中的事務(wù)順序,后續(xù)操作可以利用這個(gè)順序來完成更高層次的抽象功能,例如同步原語7。
(4)高性能(速度優(yōu)勢)
ZooKeeper特別適合于以讀為主要負(fù)荷的場合。ZooKeeper可以運(yùn)行在數(shù)千臺機(jī)器上,如果大部分操作為讀,例如讀寫比例為10:1,ZooKeeper的效率會(huì)很高。
ZooKeeper的集群
ZK集群如下圖2.1所示。這是實(shí)際應(yīng)用的一個(gè)場景,該ZooKeeper集群當(dāng)中一共有5臺服務(wù)器,有兩種角色Leader和Follwer,5臺服務(wù)器連通在一起,客戶端有分別連在不同的ZK服務(wù)器上。如果當(dāng)數(shù)據(jù)通過客戶端1,在左邊第一臺Follower服務(wù)器上做了一次數(shù)據(jù)變更,他會(huì)把這個(gè)數(shù)據(jù)的變化同步到其他所有的服務(wù)器,同步結(jié)束之后,那么其他的客戶端都會(huì)獲得這個(gè)數(shù)據(jù)的變化。
圖 2.1
注意:
通常Zookeeper由2n+1臺servers組成,每個(gè)server都知道彼此的存在。每個(gè)server都維護(hù)的內(nèi)存狀態(tài)鏡像以及持久化存儲的事務(wù)日志和快照。為了保證Leader選舉能過得到多數(shù)的支持,所以ZooKeeper集群的數(shù)量一般為奇數(shù)。對于2n+1臺server,只要有n+1臺(大多數(shù))server可用,整個(gè)系統(tǒng)保持可用。所以Zookeeper集群至少需要3臺servers服務(wù)器!
集群中的角色
在ZooKeeper集群當(dāng)中,集群中的服務(wù)器角色有兩種Leader和Learner,Learner角色又分為Observer和Follower,具體功能如下:
Leader(領(lǐng)導(dǎo)者)為客戶端提供讀和寫的服務(wù),負(fù)責(zé)投票的發(fā)起和決議,更新系統(tǒng)狀態(tài)。
Follower(跟隨者)為客戶端提供讀服務(wù),如果是寫服務(wù)則轉(zhuǎn)發(fā)給Leader。在選舉過程中參與投票。
Observe(觀察者)為客戶端提供讀服務(wù)器,如果是寫服務(wù)則轉(zhuǎn)發(fā)給Leader。不參與選舉過程中的投票,也不參與“過半寫成功”策略。在不影響寫性能的情況下提升集群的讀性能。此角色于zookeeper3.3系列新增的角色。
client(客戶端)連接zookeeper服務(wù)器的使用著,請求的發(fā)起者。獨(dú)立于zookeeper服務(wù)器集群之外的角色。
領(lǐng)導(dǎo)者(leader),負(fù)責(zé)進(jìn)行投票的發(fā)起和決議,更新系統(tǒng)狀態(tài)
學(xué)習(xí)者(learner),包括跟隨者(follower)和觀察者(observer),
客戶端(client),請求發(fā)起方
下面通過一張圖系統(tǒng)架構(gòu)圖了解一下各個(gè)角色所處的位置。
ZooKeeper的組件圖中給出了ZooKeeper服務(wù)的高層次的組件。除了請求處理器(request processor)外,構(gòu)成ZooKeeper服務(wù)的每個(gè)服務(wù)器都有一個(gè)備份。復(fù)制的數(shù)據(jù)庫(Replicateddatabase)是一個(gè)內(nèi)存數(shù)據(jù)庫,包含整個(gè)數(shù)據(jù)樹。為了可恢復(fù),更新會(huì)被log到磁盤,并且在更新這個(gè)內(nèi)存數(shù)據(jù)庫之前,先序列化到磁盤。
每個(gè)ZooKeeper都為客戶端提供服務(wù)。客戶端只連接到一個(gè)服務(wù)器,并提交請求。讀請求直接由本地的復(fù)制數(shù)據(jù)庫提供數(shù)據(jù)。對服務(wù)狀態(tài)進(jìn)行修改的請求、寫請求通過一個(gè)約定的協(xié)議進(jìn)行通訊。
作為這個(gè)協(xié)議的一部分,所有的寫請求都被傳送到一個(gè)叫“首領(lǐng)(leader)”的服務(wù)器,而其他的服務(wù)器,叫做“(隨從)followers”,follower從leader接收信息修改的提議,并同意進(jìn)行。當(dāng)leader發(fā)生故障時(shí),協(xié)議的信息層(messaginglayer)關(guān)注leader的替換,并同步到所有的follower。
ZooKeeper采用一個(gè)自定義的信息原子操作協(xié)議,由于信息層的操作是原子性的,ZooKeeper能保證本地的復(fù)制數(shù)據(jù)庫不會(huì)產(chǎn)生不一致。當(dāng)leader接收到一個(gè)寫請求,它計(jì)算出寫之后系統(tǒng)的狀態(tài),把它變成一個(gè)事務(wù)。
Zookeeper的讀寫機(jī)制和保證及特點(diǎn)
(1)ZooKeeper的讀寫機(jī)制
Zookeeper是一個(gè)由多個(gè)server組成的集群
一個(gè)leader,多個(gè)follower
每個(gè)server保存一份數(shù)據(jù)副本
全局?jǐn)?shù)據(jù)一致
分布式讀寫
更新請求轉(zhuǎn)發(fā),由leader實(shí)施
(2)ZooKeeper的保證
ZooKeeper運(yùn)行非常快而且簡單。雖然它的目標(biāo)是構(gòu)建更加復(fù)雜服務(wù)(例如同步)的基礎(chǔ),但它提供了一些保證,如下:
1.順序一致性:來自于客戶端的更新,根據(jù)發(fā)送的先后被順序?qū)嵤?/p>
2.唯一的系統(tǒng)映像:盡管客戶端連接到不同的服務(wù)器,但它們看到的一個(gè)唯一(一致性)的系統(tǒng)服務(wù),client無論連接到哪個(gè)server,數(shù)據(jù)視圖都是一致的。
3.可靠性:一旦實(shí)施了一個(gè)更新,就會(huì)一直保持那種狀態(tài),直到客戶端再次更新它,同時(shí)數(shù)據(jù)更新原子性,一次數(shù)據(jù)更新要么成功,要么失敗。
4.及時(shí)性:在一個(gè)確定的時(shí)間內(nèi),客戶端看到的系統(tǒng)狀態(tài)是最新的。
(3)ZooKeeper特點(diǎn)
最終一致性:client不論連接到哪個(gè)Server,展示給它都是同一個(gè)視圖,這是zookeeper最重要的性能。
可靠性:具有簡單、健壯、良好的性能,如果消息m被一臺服務(wù)器接受,那么它將被所有的服務(wù)器接受。
實(shí)時(shí)性:Zookeeper保證客戶端將在一個(gè)時(shí)間間隔范圍內(nèi)獲得服務(wù)器的更新信息,或者服務(wù)器失效的信息。 但由于網(wǎng)絡(luò)延時(shí)等原因,Zookeeper不能保證兩個(gè)客戶端能同時(shí)得到剛更新的數(shù)據(jù),如果需要最新數(shù)據(jù),應(yīng)該在讀數(shù)據(jù)之前調(diào)用sync()接口!!
等待無關(guān)(wait-free):慢的或者失效的client,不得干預(yù)快速的client的請求,使得每個(gè)client都能有效的等待。
原子性:更新只能成功或者失敗,沒有中間狀態(tài)。
順序性:包括全局有序和偏序兩種:
全局有序:是指如果在一臺服務(wù)器上消息a在消息b前發(fā)布,則在所有Server上消息a都將在消息b前被發(fā)布;
偏序:是指如果一個(gè)消息b在消息a后被同一個(gè)發(fā)送者發(fā)布,a必將排在b前面
ZooKeeper服務(wù)
ZooKeeper擁有一個(gè)層次的命名空間,這個(gè)和分布式的文件系統(tǒng)非常相似。不同的是ZooKeeper命名空間中的Znode,兼具文件和目錄兩種特點(diǎn)。既像文件一樣維護(hù)著數(shù)據(jù)、元信息、ACL、時(shí)間戳等數(shù)據(jù)結(jié)構(gòu),又像目錄一樣可以作為路徑標(biāo)識的一部分,并可以具有子znode。用戶對znode具有增、刪、改、查等操作(權(quán)限允許的情況下)。
znode具有原子性操作,每個(gè)znode的數(shù)據(jù)將被原子性地讀寫,讀操作會(huì)讀取與znode相關(guān)的所有數(shù)據(jù),寫操作會(huì)一次性替換所有數(shù)據(jù)。zookeeper并沒有被設(shè)計(jì)為常規(guī)的數(shù)據(jù)庫或者大數(shù)據(jù)存儲,相反的是,它用來管理調(diào)度數(shù)據(jù),比如分布式應(yīng)用中的配置文件信息、狀態(tài)信息、匯集位置等等。這些數(shù)據(jù)的共同特性就是它們都是很小的數(shù)據(jù),通常以KB為大小單位。zooKeeper的服務(wù)器和客戶端都被設(shè)計(jì)為嚴(yán)格檢查并限制每個(gè)znode的數(shù)據(jù)大小至多1M,當(dāng)時(shí)常規(guī)使用中應(yīng)該遠(yuǎn)小于此值。
Zonde由路徑標(biāo)注,ZooKeeper中被表示成有反斜杠分割的Unicode字符串,如同Unix中的文件路徑。路徑必須是絕對的,因此他們必須由反斜杠來字符開頭。除此以外,他們必須是唯一的,也就是說每一個(gè)路徑只有一個(gè)表示,因此這些路徑不能改變。ZooKeeper的數(shù)據(jù)結(jié)構(gòu), 與普通的文件系統(tǒng)極為類似. 見下圖:
圖中的每個(gè)節(jié)點(diǎn)稱為一個(gè)znode. 每個(gè)znode由3部分組成:
1.stat:此為狀態(tài)信息, 描述該znode的版本, 權(quán)限等信息.
2.data:與該znode關(guān)聯(lián)的數(shù)據(jù).
3.children:該znode下的子節(jié)點(diǎn).
ZooKeeper節(jié)點(diǎn)Znode
ZooKeeper目錄樹中每一個(gè)節(jié)點(diǎn)對應(yīng)一個(gè)Znode。每個(gè)Znode維護(hù)著一個(gè)屬性結(jié)構(gòu),它包含著版本號(dataVersion),時(shí)間戳(ctime,mtime)等狀態(tài)信息。ZooKeeper正是使用節(jié)點(diǎn)的這些特性來實(shí)現(xiàn)它的某些特定功能。每當(dāng)Znode的數(shù)據(jù)改變時(shí),他相應(yīng)的版本號將會(huì)增加。每當(dāng)客戶端檢索數(shù)據(jù)時(shí),它將同時(shí)檢索數(shù)據(jù)的版本號。并且如果一個(gè)客戶端執(zhí)行了某個(gè)節(jié)點(diǎn)的更新或刪除操作,他也必須提供要被操作的數(shù)據(jù)版本號。如果所提供的數(shù)據(jù)版本號與實(shí)際不匹配,那么這個(gè)操作將會(huì)失敗。
Znode是客戶端訪問ZooKeeper的主要實(shí)體,它包含以下幾個(gè)特征:
(1)Watches
客戶端可以在節(jié)點(diǎn)上設(shè)置watch(我們稱之為監(jiān)視器)。當(dāng)節(jié)點(diǎn)狀態(tài)發(fā)生改變時(shí)(數(shù)據(jù)的增、刪、改)將會(huì)觸發(fā)watch所對應(yīng)的操作。當(dāng)watch被觸發(fā)時(shí),ZooKeeper將會(huì)向客戶端發(fā)送且僅發(fā)送一條通知,因?yàn)閣atch只能被觸發(fā)一次。
(2)數(shù)據(jù)訪問
ZooKeeper中的每個(gè)節(jié)點(diǎn)存儲的數(shù)據(jù)要被原子性的操作。也就是說讀操作將獲取與節(jié)點(diǎn)相關(guān)的所有數(shù)據(jù),寫操作也將替換掉節(jié)點(diǎn)的所有數(shù)據(jù)。另外,每一個(gè)節(jié)點(diǎn)都擁有自己的ACL(訪問控制列表),這個(gè)列表規(guī)定了用戶的權(quán)限,即限定了特定用戶對目標(biāo)節(jié)點(diǎn)可以執(zhí)行的操作。
(3)節(jié)點(diǎn)類型
ZooKeeper中的節(jié)點(diǎn)有兩種,分別為臨時(shí)節(jié)點(diǎn)和永久節(jié)點(diǎn)。節(jié)點(diǎn)的類型在創(chuàng)建時(shí)即被確定,并且不能改變。ZooKeeper的臨時(shí)節(jié)點(diǎn):該節(jié)點(diǎn)的生命周期依賴于創(chuàng)建它們的會(huì)話。一旦會(huì)話結(jié)束,臨時(shí)節(jié)點(diǎn)將被自動(dòng)刪除,當(dāng)然可以也可以手動(dòng)刪除。另外,需要注意是,ZooKeeper的臨時(shí)節(jié)點(diǎn)不允許擁有子節(jié)點(diǎn)。ZooKeeper的永久節(jié)點(diǎn):該節(jié)點(diǎn)的生命周期不依賴于會(huì)話,并且只有在客戶端顯示執(zhí)行刪除操作的時(shí)候,他們才能被刪除。
(4)順序節(jié)點(diǎn)(唯一性的保證)
當(dāng)創(chuàng)建Znode的時(shí)候,用戶可以請求在ZooKeeper的路徑結(jié)尾添加一個(gè)遞增的計(jì)數(shù)。這個(gè)計(jì)數(shù)對于此節(jié)點(diǎn)的父節(jié)點(diǎn)來說是唯一的,它的格式為“%10d”(10位數(shù)字,沒有數(shù)值的數(shù)位用0補(bǔ)充,例如“0000000001”)。當(dāng)計(jì)數(shù)值大于232-1時(shí),計(jì)數(shù)器將溢出。
org.apache.zookeeper.CreateMode中定義了四種節(jié)點(diǎn)類型,分別對應(yīng):
PERSISTENT:永久節(jié)點(diǎn)
EPHEMERAL:臨時(shí)節(jié)點(diǎn)
PERSISTENT_SEQUENTIAL:永久節(jié)點(diǎn)、序列化
EPHEMERAL_SEQUENTIAL:臨時(shí)節(jié)點(diǎn)、序列化
ZooKeeper中的時(shí)間
ZooKeeper有多種記錄時(shí)間的形式,其中包含以下幾個(gè)主要屬性:
(1)Zxid
致使ZooKeeper節(jié)點(diǎn)狀態(tài)改變的每一個(gè)操作都將使節(jié)點(diǎn)接收到一個(gè)zxid格式的時(shí)間戳,并且這個(gè)時(shí)間戳全局有序。也就是說,也就是說,每個(gè)對節(jié)點(diǎn)的改變都將產(chǎn)生一個(gè)唯一的zxid。如果zxid1的值小于zxid2的值,那么zxid1所對應(yīng)的事件發(fā)生在zxid2所對應(yīng)的事件之前。實(shí)際上,ZooKeeper的每個(gè)節(jié)點(diǎn)維護(hù)者三個(gè)zxid值,為別為:cZxid、mZxid、pZxid。
cZxid: 是節(jié)點(diǎn)的創(chuàng)建時(shí)間所對應(yīng)的Zxid格式時(shí)間戳。
mZxid:是節(jié)點(diǎn)的修改時(shí)間所對應(yīng)的Zxid格式時(shí)間戳,與其子節(jié)點(diǎn)無關(guān)。
pZxid:該節(jié)點(diǎn)的子節(jié)點(diǎn)(或該節(jié)點(diǎn))的最近一次 創(chuàng)建 / 刪除 的修改時(shí)間所對應(yīng)的cZxid格式時(shí)間戳(注:只與 本節(jié)點(diǎn)/該節(jié)點(diǎn)的子節(jié)點(diǎn),有關(guān);與孫子節(jié)點(diǎn)無關(guān)).
實(shí)現(xiàn)中zxid是一個(gè)64位的數(shù)字,它高32位是epoch用來標(biāo)識leader關(guān)系是否改變,每次一個(gè)leader被選出來,它都會(huì)有一個(gè) 新的epoch。低32位是個(gè)遞增計(jì)數(shù)。
(2)版本號
對節(jié)點(diǎn)的每一個(gè)操作都將致使這個(gè)節(jié)點(diǎn)的版本號增加。每個(gè)節(jié)點(diǎn)維護(hù)著三個(gè)版本號,他們分別為:
version 節(jié)點(diǎn)數(shù)據(jù)版本號
cversion 子節(jié)點(diǎn)版本號
aversion 節(jié)點(diǎn)所擁有的ACL版本號
節(jié)點(diǎn)的屬性結(jié)構(gòu)
通過前面的介紹,我們可以了解到,一個(gè)節(jié)點(diǎn)自身擁有表示其狀態(tài)的許多重要屬性,如下圖所示。
Zonde總結(jié)
(1)znode中的數(shù)據(jù)可以有多個(gè)版本,在查詢該znode數(shù)據(jù)時(shí)就需要帶上版本信息。如:set path version / delete path version
(2)znode可以是臨時(shí)znode,由create -e 生成的節(jié)點(diǎn),一旦創(chuàng)建這個(gè)znode的client與server斷開連接,該znode將被自動(dòng)刪除。
client和server之間通過heartbeat來確認(rèn)連接正常,這種狀態(tài)稱之為session,斷開連接后session失效。
(3)臨時(shí)znode不能有子znode。
(4)znode可以自動(dòng)編號,由create -s 生成的節(jié)點(diǎn),例如在 create -s /app/node 已存在時(shí),將會(huì)生成 /app/node00***001節(jié)點(diǎn)。
(5)znode可以被監(jiān)控,該目錄下某些信息的修改,例如節(jié)點(diǎn)數(shù)據(jù)、子節(jié)點(diǎn)變化等,可以主動(dòng)通知監(jiān)控注冊的client。事實(shí)上,通過這個(gè)特性,可以完成許多重要應(yīng)用,例如配置管理、信息同步、分布式鎖等等。
ZooKeeper服務(wù)中的操作
在ZooKeeper中有9個(gè)基本操作,如下圖所示:
更新ZooKeeper操作是有限制的。delete或setData必須明確要更新的Znode的版本號,我們可以調(diào)用exists找到。如果版本號不匹配,更新將會(huì)失敗。
更新ZooKeeper操作是非阻塞式的。因此客戶端如果失去了一個(gè)更新(由于另一個(gè)進(jìn)程在同時(shí)更新這個(gè)Znode),他可以在不阻塞其他進(jìn)程執(zhí)行的情況下,選擇重新嘗試或進(jìn)行其他操作。
盡管ZooKeeper可以被看做是一個(gè)文件系統(tǒng),但是處于便利,摒棄了一些文件系統(tǒng)地操作原語。因?yàn)槲募浅5男〔⑶沂拐w讀寫的,所以不需要打開、關(guān)閉或是尋地的操作。
watch觸發(fā)器
讀操作exists、getChildren和getData都被設(shè)置了watch,并且這些watch都由寫操作來觸發(fā):create、delete和setData。ACL操作并不參與到watch中。當(dāng)watch被觸發(fā)時(shí),watch事件被生成,他的類型由watch和觸發(fā)他的操作共同決定。ZooKeeper所管理的watch可以分為兩類:
1.數(shù)據(jù)watch(data watches):getData和exists負(fù)責(zé)設(shè)置數(shù)據(jù)watch;
2.孩子watch(child watches):getChildren負(fù)責(zé)設(shè)置孩子watch;
我們可以通過操作返回的數(shù)據(jù)來設(shè)置不同的watch:
1.getData和exists:返回關(guān)于節(jié)點(diǎn)的數(shù)據(jù)信息
2.getChildren:返回孩子列表
因此,一個(gè)成功的setData操作將觸發(fā)Znode的數(shù)據(jù)watch。
一個(gè)成功的create操作將觸發(fā)Znode的數(shù)據(jù)watch以及孩子watch。
一個(gè)成功的delete操作將觸發(fā)Znode的數(shù)據(jù)watch以及孩子watch。
watch由客戶端所連接的ZooKeeper服務(wù)器在本地維護(hù),因此watch可以非常容易地設(shè)置、管理和分派。當(dāng)客戶端連接到一個(gè)新的服務(wù)器上時(shí),任何的會(huì)話事件都將可能觸發(fā)watch。另外,當(dāng)從服務(wù)器斷開連接的時(shí)候,watch將不會(huì)被接收。但是,當(dāng)一個(gè)客戶端重新建立連接的時(shí)候,任何先前注冊過的watch都會(huì)被重新注冊。
exists操作上的watch,在被監(jiān)視的Znode創(chuàng)建、刪除或數(shù)據(jù)更新時(shí)被觸發(fā)。
getData操作上的watch,在被監(jiān)視的Znode刪除或數(shù)據(jù)更新時(shí)被觸發(fā)。在被創(chuàng)建時(shí)不能被觸發(fā),因?yàn)橹挥衂node一定存在,getData操作才會(huì)成功。
getChildren操作上的watch,在被監(jiān)視的Znode的子節(jié)點(diǎn)創(chuàng)建或刪除,或是這個(gè)Znode自身被刪除時(shí)被觸發(fā)。可以通過查看watch事件類型來區(qū)分是Znode還是他的子節(jié)點(diǎn)被刪除:NodeDelete表示Znode被刪除,NodeDeletedChanged表示子節(jié)點(diǎn)被刪除。
watch設(shè)置操作及相應(yīng)的觸發(fā)器如圖下圖所示:
watch事件包括了事件所涉及的Znode的路徑,因此對于NodeCreated和NodeDeleted事件來說,根據(jù)路徑就可以簡單區(qū)分出是哪個(gè)Znode被創(chuàng)建或是被刪除了。為了查詢在NodeChildrenChanged事件后哪個(gè)子節(jié)點(diǎn)被改變了,需要再次調(diào)用getChildren來獲得新的children列表。同樣的,為了查詢NodeDeletedChanged事件后產(chǎn)生的新數(shù)據(jù),需要調(diào)用getData。在兩種情況下,Znode可能在獲取watch事件或執(zhí)行讀操作這兩種狀態(tài)下切換,在寫應(yīng)用程序時(shí),必須記住這一點(diǎn)。
(1)Zookeeper的watch實(shí)際上要處理兩類事件:
1. 連接狀態(tài)事件(type=None, path=null)
這類事件不需要注冊,也不需要我們連續(xù)觸發(fā),我們只要處理就行了。
2. 節(jié)點(diǎn)事件
節(jié)點(diǎn)的建立,刪除,數(shù)據(jù)的修改。它是one time trigger,我們需要不停的注冊觸發(fā),還可能發(fā)生事件丟失的情況。
上面2類事件都在Watch中處理,也就是重載的process(Event event)
(2)節(jié)點(diǎn)事件的觸發(fā),通過函數(shù)exists,getData或getChildren來處理
這類函數(shù),有雙重作用:
1. 注冊觸發(fā)事件
2. 函數(shù)本身的功能
函數(shù)的本身的功能又可以用異步的回調(diào)函數(shù)來實(shí)現(xiàn),重載processResult()過程中處理函數(shù)本身的的功能。
函數(shù)還可以指定自己的watch,所以每個(gè)函數(shù)都有4個(gè)版本。根據(jù)自己的需要來選擇不同的函數(shù),不同的版本。
watcherWatcher我們可以理解為他是一個(gè)事件監(jiān)聽器。
ZooKeeper允許用戶在指定節(jié)點(diǎn)上注冊一些watcher,當(dāng)數(shù)據(jù)節(jié)點(diǎn)發(fā)生變化的時(shí)候,Zookeeper服務(wù)器會(huì)把這個(gè)變化的通知發(fā)送給感興趣的客戶端。
兩個(gè)客戶端都在zookeeper集群中注冊了watcher(事件監(jiān)聽器),那么當(dāng)zk中的節(jié)點(diǎn)數(shù)據(jù)發(fā)生變化的時(shí)候,zk會(huì)把這一變化的通知發(fā)送給客戶端,當(dāng)客戶端收到這個(gè)變化通知的時(shí)候,它可以再回到zk中,去取得這個(gè)數(shù)據(jù)的詳細(xì)信息。
ZooKeeper訪問控制列表ACL
ZooKeeper使用ACL來對Znode進(jìn)行訪問控制。ACL的實(shí)現(xiàn)和Unix文件訪問許可非常相似:它使用許可位來對一個(gè)節(jié)點(diǎn)的不同操作進(jìn)行允許或禁止的權(quán)限控制。但是,和標(biāo)準(zhǔn)的Unix許可不同的是,Zookeeper對于用戶類別的區(qū)分,不止局限于所有者(owner)、組 (group)、所有人(world)三個(gè)級別。Zookeeper中,數(shù)據(jù)節(jié)點(diǎn)沒有“所有者”的概念。訪問者利用id標(biāo)識自己的身份,并獲得與之相應(yīng)的 不同的訪問權(quán)限。
注意:
傳統(tǒng)的文件系統(tǒng)中,ACL分為兩個(gè)維度,一個(gè)是屬組,一個(gè)是權(quán)限,子目錄/文件默認(rèn)繼承父目錄的ACL。而在Zookeeper中一個(gè)ACL和一個(gè)ZooKeeper節(jié)點(diǎn)相對應(yīng)。并且,父節(jié)點(diǎn)的ACL與子節(jié)點(diǎn)的ACL是相互獨(dú)立的。也就是說,ACL不能被子節(jié)點(diǎn)所繼承,父節(jié)點(diǎn)所擁有的權(quán)限與子節(jié)點(diǎn)所用的權(quán)限都沒有任何關(guān)系。
Zookeeper支持可配置的認(rèn)證機(jī)制。它利用一個(gè)三元組來定義客戶端的訪問權(quán)限:(scheme:expression, perms)。其中:
1.scheme:定義了expression的含義。
如:(host:host1.corp.com,READ),標(biāo)識了一個(gè)名為host1.corp.com的主機(jī),有該數(shù)據(jù)節(jié)點(diǎn)的讀權(quán)限。
2.Perms:標(biāo)識了操作權(quán)限。
如:(ip:19.22.0.0/16, READ),表示IP地址以19.22開頭的主機(jī),有該數(shù)據(jù)節(jié)點(diǎn)的讀權(quán)限。
Zookeeper的ACL也可以從三個(gè)維度來理解:一是,scheme; 二是,user; 三是,permission,通常表示為scheme:id:permissions,如下圖所示。
1.world : id格式:anyone。
如:world:anyone代表任何人,zookeeper中對所有人有權(quán)限的結(jié)點(diǎn)就是屬于world:anyone的。
2.auth : 它不需要id。
注:只要是通過authentication的user都有權(quán)限,zookeeper支持通過kerberos來進(jìn)行認(rèn)證, 也支持username/password形式的認(rèn)證。
3.digest: id格式:username:BASE64(SHA1(password))。
它需要先通過username:password形式的authentication。
4.ip: id格式:客戶機(jī)的IP地址。
設(shè)置的時(shí)候可以設(shè)置一個(gè)ip段。如:ip:192.168.1.0/16, 表示匹配前16個(gè)bit的IP段
5.super: 超級用戶模式。
在這種scheme情況下,對應(yīng)的id擁有超級權(quán)限,可以做任何事情
ZooKeeper權(quán)限定義如下圖所示:
ZooKeeper內(nèi)置的ACL模式如下圖所示,ACL是Access Control Lists 的簡寫, ZooKeeper采用ACL策略來進(jìn)行權(quán)限控制:
當(dāng)會(huì)話建立的時(shí)候,客戶端將會(huì)進(jìn)行自我驗(yàn)證。另外,ZooKeeper Java API支持三種標(biāo)準(zhǔn)的用戶權(quán)限,它們分別為:
1.ZOO_PEN_ACL_UNSAFE:對于所有的ACL來說都是完全開放的,任何應(yīng)用程序可以在節(jié)點(diǎn)上執(zhí)行任何操作,比如創(chuàng)建、列出并刪除子節(jié)點(diǎn)。
2.ZOO_READ_ACL_UNSAFE:對于任意的應(yīng)用程序來說,僅僅具有讀權(quán)限。
3.ZOO_CREATOR_ALL_ACL:授予節(jié)點(diǎn)創(chuàng)建者所有權(quán)限。需要注意的是,設(shè)置此權(quán)限之前,創(chuàng)建者必須已經(jīng)通了服務(wù)器的認(rèn)證。
ZooKeeper的執(zhí)行
ZooKeeper服務(wù)可以以兩種模式運(yùn)行。在單機(jī)模式下,只有一個(gè)ZooKeeper服務(wù)器,便于用來測試。但是他沒有高可用性和恢復(fù)性的保障。在工業(yè)界,ZooKeeper以復(fù)合模式10運(yùn)行在一組叫ensemble的集群上。ZooKeeper通過復(fù)制來獲得高可用性,同時(shí),只要ensemble中大部分機(jī)器運(yùn)作,就可以提供服務(wù)。在2n+1個(gè)節(jié)點(diǎn)的ensemble中,可以承受n臺機(jī)器故障。
ZooKeeper的思想非常簡單:他所需要做的就是保證對Znode樹的每一次修改都復(fù)制到ensemble中的大部分機(jī)器上去。如果機(jī)器中的小部分出故障了,那么至少有一臺機(jī)器將會(huì)恢復(fù)到最新狀態(tài),其他的則保存這副本,直到最終達(dá)到最新狀態(tài)。Zookeeper采用Zab協(xié)議,它分為兩個(gè)階段,并且可能被無限的重復(fù)。
(1)階段1:領(lǐng)導(dǎo)者選舉
在ensemble中的機(jī)器要參與一個(gè)選擇特殊成員的進(jìn)程,這個(gè)成員叫領(lǐng)導(dǎo)者,其他機(jī)器腳跟隨者。在大部分的跟隨者與他們的領(lǐng)導(dǎo)者同步了狀態(tài)以后,這個(gè)階段才算完成。
(2)階段2:原子廣播
所有的寫操作請求被傳送給領(lǐng)導(dǎo)者,并通過廣播將更新信息告訴跟隨者。當(dāng)大部分跟隨者執(zhí)行了修改之后,領(lǐng)導(dǎo)者就提交更新操作,客戶端將得到更新成功的回應(yīng)。未獲得一致性的協(xié)議被設(shè)計(jì)為原子的,因此無論修改失敗與否,他都分兩階段提交。
如果領(lǐng)導(dǎo)者出故障了,城下的機(jī)器將會(huì)再次進(jìn)行領(lǐng)導(dǎo)者選舉,并在新領(lǐng)導(dǎo)被選出前繼續(xù)執(zhí)行任務(wù)。如果在不久后老的領(lǐng)導(dǎo)者恢復(fù)了,那么它將以跟隨者的身份繼續(xù)運(yùn)行。領(lǐng)導(dǎo)者選舉非常快,由發(fā)布的結(jié)果所知,大約是200毫秒,因此在選舉是性能不會(huì)明顯減慢。所有在ensemble中的機(jī)器在更新它們內(nèi)存中的Znode樹之前會(huì)先將更新信息寫入磁盤。讀操作請求可由任何機(jī)器服務(wù),同時(shí),由于他們只涉及內(nèi)存查找,因此非常快。
ZooKeeper一致性
在ensemble中的領(lǐng)導(dǎo)者和跟隨著非常靈活,跟隨者通過更新號來滯后領(lǐng)導(dǎo)者11,結(jié)果導(dǎo)致了只要大部分而不是所有的ensemble中的元素確認(rèn)更新,就能被提交了。對于ZooKeeper來說,一個(gè)較好的智能模式是將客戶端連接到跟著領(lǐng)導(dǎo)者的ZooKeeper服務(wù)器上。客戶端可能被連接到領(lǐng)導(dǎo)者上,但他不能控制它,而且在如下情況時(shí),甚至可能不知道。參見下圖:
每一個(gè)Znode樹的更新都會(huì)給定一個(gè)唯一的全局標(biāo)識,叫zxid(表示ZooKeeper事務(wù)“ID”)。更新是被排序的,因此如果zxid的z1<z2,那么z1就比z2先執(zhí)行。對于ZooKeeper來說,這是分布式系統(tǒng)中排序的唯一標(biāo)準(zhǔn)。
ZooKeeper是一種高性能、可擴(kuò)展的服務(wù)。ZooKeeper的讀寫速度非常快,并且讀的速度要比寫快。另外,在進(jìn)行讀操作的時(shí)候,ZooKeeper依然能夠?yàn)榕f的數(shù)據(jù)提供服務(wù)。這些都是由ZooKeeper所提供的一致性保證的,它具有如下特點(diǎn):
(1)順序一致性
任何一個(gè)客戶端的更新都按他們發(fā)送的順序排序,也就意味著如果一個(gè)客戶端將Znode z的值更新為值a,那么在之后的操作中,他會(huì)將z更新為b,在客戶端發(fā)現(xiàn)z帶有值b之后,就不會(huì)再看見帶有值a的z。
(2)原子性
更新不成功就失敗,這意味著如果更新失敗了,沒有客戶端會(huì)知道。☆☆
(3)單系統(tǒng)映像☆
無論客戶端連接的是哪臺服務(wù)器,他與系統(tǒng)看見的視圖一樣。這就意味著,如果一個(gè)客戶端在相同的會(huì)話時(shí)連接了一臺新的服務(wù)器,他將不會(huì)再看見比在之前服務(wù)器上看見的更老的系統(tǒng)狀態(tài),當(dāng)服務(wù)器系統(tǒng)出故障,同時(shí)客戶端嘗試連接ensemble中的其他機(jī)器時(shí),故障服務(wù)器的后面那臺機(jī)器將不會(huì)接受連接,直到它連接到故障服務(wù)器。
(4)容錯(cuò)性☆☆☆
一旦更新成功后,那么在客戶端再次更新他之前,他就固定了,將不再被修改,這就會(huì)保證產(chǎn)生下面兩種結(jié)果:
如果客戶端成功的獲得了正確的返回代碼,那么說明更新已經(jīng)成功。如果不能夠獲得返回代碼(由于通信錯(cuò)誤、超時(shí)等原因),那么客戶端將不知道更新是否生效。
當(dāng)故障恢復(fù)的時(shí)候,任何客戶端能夠看到的執(zhí)行成功的更新操作將不會(huì)回滾。
(5)實(shí)時(shí)性☆☆
在任何客戶端的系統(tǒng)視圖上的的時(shí)間間隔是有限的,因此他在超過幾十秒的時(shí)間內(nèi)部會(huì)過期。這就意味著,服務(wù)器不會(huì)讓客戶端看一些過時(shí)的數(shù)據(jù),而是關(guān)閉,強(qiáng)制客戶端轉(zhuǎn)到一個(gè)更新的服務(wù)器上。
解釋一下:
由于性能原因,讀操作由ZooKeeper服務(wù)器的內(nèi)存提供,而且不參與寫操作的全局排序。這一特性可能會(huì)導(dǎo)致來自使用ZooKeeper外部機(jī)制交流的客戶端與ZooKeeper狀態(tài)的不一致。舉例來說,客戶端A將Znode z的值a更新為a’,A讓B來讀z,B讀到z的值是a而不是a’。這與ZooKeeper的保證機(jī)制是相容的(不允許的情況較作“同步一致的交叉客戶端視 圖”)。為了避免這種情況的發(fā)生,B在讀取z的值之前,應(yīng)該先調(diào)用z上的sync。Sync操作強(qiáng)制B連接上的ZooKeeper服務(wù)器與leader保 持一致這樣,當(dāng)B讀到z的值時(shí),他將成為A設(shè)置的值(或是之后的值)
容易混淆的是:
sync操作只能被異步調(diào)用。這樣操作的原因是你不需要等待他的返回,因?yàn)閆ooKeeper保證了任何接下去的操作將會(huì)發(fā)生在sync在服務(wù)器上執(zhí)行以后,即使操作是在sync完成前被調(diào)用的。
這些已執(zhí)行的保證后,ZooKeeper更高級功能的設(shè)計(jì)與實(shí)現(xiàn)將會(huì)變得非常容易,例如:leader選舉、隊(duì)列,以及可撤銷鎖等機(jī)制的實(shí)現(xiàn)。
ZooKeeper會(huì)話
ZooKeeper客戶端與ensemble中的服務(wù)器列表配置一致,在啟動(dòng)時(shí),他嘗試與表中的一個(gè)服務(wù)器相連接。如果連接失敗了,他就嘗試表中的其他服務(wù)器,以此類推,知道他最終連接到其中一個(gè),或者ZooKeeper的所有服務(wù)器都無法獲得時(shí),連接失敗。
一旦與ZooKeeper服務(wù)器連接成功,服務(wù)器會(huì)創(chuàng)建與客戶端的一個(gè)新的對話。每個(gè)回話都有超時(shí)時(shí)段,這是應(yīng)用程序在創(chuàng)建它時(shí)設(shè)定的。如果服務(wù)器沒有在超時(shí)時(shí)段內(nèi)得到請求,他可能會(huì)中斷這個(gè)會(huì)話。一旦會(huì)話被中斷了,他可能不再被打開,而且任何與會(huì)話相連接的臨時(shí)節(jié)點(diǎn)都將丟失。
無論什么時(shí)候會(huì)話持續(xù)空閑長達(dá)一定時(shí)間,都會(huì)由客戶端發(fā)送ping請求保持活躍(猶如心跳)。時(shí)間段要足夠小以監(jiān)測服務(wù)器故障(由讀操作超時(shí)反應(yīng)),并且能再回話超時(shí)時(shí)間段內(nèi)重新連接到另一個(gè)服務(wù)器。
在ZooKeeper中有幾個(gè)time參數(shù)。tick time是ZooKeeper中的基本時(shí)間長度,為ensemble里的服務(wù)器所使用,用來定義對于交互運(yùn)行的調(diào)度。其他設(shè)置以tick time的名義定義,或者至少由它來約束。
創(chuàng)建更復(fù)雜的臨時(shí)性狀態(tài)的應(yīng)用程序應(yīng)該支持更長的會(huì)話超時(shí),因?yàn)橹匦聵?gòu)建的代價(jià)會(huì)更昂貴。在一些情況下,我們可以讓應(yīng)用程序在一定會(huì)話時(shí)間內(nèi)能夠重啟,并且避免會(huì)話過期。(這可能更適合執(zhí)行維護(hù)或是升級)每個(gè)會(huì)話都由服務(wù)器給定一個(gè)唯一的身份和密碼,而且如果是在建立連接時(shí)被傳遞給ZooKeeper的話,只要沒有過期它能夠恢復(fù)會(huì)話。
這些特性可以視為一種可以避免會(huì)話過期的優(yōu)化,但它并不能代替用來處理會(huì)話過期。會(huì)話過期可能出現(xiàn)在機(jī)器突然故障時(shí),或是由于任何原因?qū)е碌膽?yīng)用程序安全關(guān)閉了,但在會(huì)話中斷前沒有重啟。
ZooKeeper實(shí)例狀態(tài)
Zookeeper對象的轉(zhuǎn)變是通過其生命周期中的不同狀態(tài)來實(shí)現(xiàn)。可以使用getState()方法在任何時(shí)候去查詢他的狀態(tài):
Zookeeper狀態(tài)事務(wù),如圖3.5所示
圖 3.5 Zookeeper狀態(tài)事務(wù)
getState()方法的返回類型是states,states是枚舉類型代表Zookeeper對象可能所處的不同狀態(tài),一個(gè)Zookeeper實(shí)例可能一次只處于一個(gè)狀態(tài)。一個(gè)新建的Zookeeper實(shí)例正在于Zookeeper服務(wù)器建立連接時(shí),是處于CONNECTING狀態(tài)的。一旦連接建立好以后,他就變成了Connected狀態(tài)。
使用Zookeeper的客戶端可以通過注冊Watcher的方法來獲取狀態(tài)轉(zhuǎn)變的消息。一旦進(jìn)入了CONNNECTED狀態(tài),Watcher將獲得一個(gè)KeepState值為SyncConnected的WatchedEvent。
注意Zookeeper的watcher有兩個(gè)職責(zé):
<1>了解Zookeeper的狀態(tài)改變。傳遞給ZooKeeper對象構(gòu)造函數(shù)的(默認(rèn))watcher,被用來監(jiān)測狀態(tài)的改變。
<2>了解Zonde的改變。監(jiān)測Zonde的改變既可以使用專門的實(shí)例設(shè)置到讀操作上,也可以使用讀操作的默認(rèn)watcher。
Zookeeper實(shí)例可能失去或重新連接Zookeeper服務(wù),在CONNECTED和CONNECTING狀態(tài)中切換。如果連接斷開,watcher得到一個(gè)Disconnected事件。學(xué)要注意的是,這些狀態(tài)的遷移是由Zookeeper實(shí)例自己發(fā)起的,如果連接斷開他將自動(dòng)嘗試自動(dòng)連接。
如果任何一個(gè)close()方法被調(diào)用,或是會(huì)話由Expired類型的KeepState提示過期時(shí),ZooKeeper可能會(huì)轉(zhuǎn)變成第三種狀態(tài)CLOSED。一旦處于CLOSED狀態(tài),Zookeeper對象將不再是活動(dòng)的了(可以使用states的isActive()方法進(jìn)行測試),而且不能被重用。客戶端必須建立一個(gè)新的Zookeeper實(shí)例才能重新連接到Zookeeper服務(wù)。
【參原文】https://baijiahao.baidu.com/s?id=1594438991585121454&wfr=spider&for=pc