ZooKeeper是一個開放源碼的分佈式協調服務,它是集羣的管理者,監視着集羣中各個節點的狀態根據節點提交的反饋進行下一步合理操做。最終,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。java
分佈式應用程序能夠基於Zookeeper實現諸如數據發佈/訂閱、負載均衡、命名服務、分佈式協調/通知、集羣管理、Master選舉、分佈式鎖和分佈式隊列等功能。node
Zookeeper保證了以下分佈式一致性特性:nginx
一、順序一致性
二、原子性
三、單一視圖
四、可靠性
五、實時性(最終一致性)算法
客戶端的讀請求能夠被集羣中的任意一臺機器處理,若是讀請求在節點上註冊了監聽器,這個監聽器也是由所鏈接的zookeeper機器來處理。對於寫請求,這些請求會同時發給其餘zookeeper機器而且達成一致後,請求才會返回成功。所以,隨着zookeeper的集羣機器增多,讀請求的吞吐會提升可是寫請求的吞吐會降低。數據庫
有序性是zookeeper中很是重要的一個特性,全部的更新都是全局有序的,每一個更新都有一個惟一的時間戳,這個時間戳稱爲zxid(Zookeeper Transaction Id)。而讀請求只會相對於更新有序,也就是讀請求的返回結果中會帶有這個zookeeper最新的zxid。設計模式
一、文件系統
二、通知機制緩存
Zookeeper提供一個多層級的節點命名空間(節點稱爲znode)。與文件系統不一樣的是,這些節點均可以設置關聯的數據,而文件系統中只有文件節點能夠存放數據而目錄節點不行。
Zookeeper爲了保證高吞吐和低延遲,在內存中維護了這個樹狀的目錄結構,這種特性使得Zookeeper不能用於存放大量的數據,每一個節點的存放數據上限爲1M。服務器
ZAB協議是爲分佈式協調服務Zookeeper專門設計的一種支持崩潰恢復的原子廣播協議。網絡
ZAB協議包括兩種基本的模式:崩潰恢復和消息廣播。session
當整個zookeeper集羣剛剛啓動或者Leader服務器宕機、重啓或者網絡故障致使不存在過半的服務器與Leader服務器保持正常通訊時,全部進程(服務器)進入崩潰恢復模式,首先選舉產生新的Leader服務器,而後集羣中Follower服務器開始與新的Leader服務器進行數據同步,當集羣中超過半數機器與該Leader服務器完成數據同步以後,退出恢復模式進入消息廣播模式,Leader服務器開始接收客戶端的事務請求生成事物提案來進行事務請求處理。
一、PERSISTENT-持久節點
除非手動刪除,不然節點一直存在於Zookeeper上
二、EPHEMERAL-臨時節點
臨時節點的生命週期與客戶端會話綁定,一旦客戶端會話失效(客戶端與zookeeper鏈接斷開不必定會話失效),那麼這個客戶端建立的全部臨時節點都會被移除。
三、PERSISTENT_SEQUENTIAL-持久順序節點
基本特性同持久節點,只是增長了順序屬性,節點名後邊會追加一個由父節點維護的自增整型數字。
四、EPHEMERAL_SEQUENTIAL-臨時順序節點
基本特性同臨時節點,增長了順序屬性,節點名後邊會追加一個由父節點維護的自增整型數字。
Zookeeper容許客戶端向服務端的某個Znode註冊一個Watcher監聽,當服務端的一些指定事件觸發了這個Watcher,服務端會向指定客戶端發送一個事件通知來實現分佈式的通知功能,而後客戶端根據Watcher通知狀態和事件類型作出業務上的改變。
工做機制:
一、客戶端註冊watcher
二、服務端處理watcher
三、客戶端回調watcher
Watcher特性總結:
一、一次性
不管是服務端仍是客戶端,一旦一個Watcher被觸發,Zookeeper都會將其從相應的存儲中移除。這樣的設計有效的減輕了服務端的壓力,否則對於更新很是頻繁的節點,服務端會不斷的向客戶端發送事件通知,不管對於網絡仍是服務端的壓力都很是大。
二、客戶端串行執行
客戶端Watcher回調的過程是一個串行同步的過程。
三、輕量
3.一、Watcher通知很是簡單,只會告訴客戶端發生了事件,而不會說明事件的具體內容。
3.二、客戶端向服務端註冊Watcher的時候,並不會把客戶端真實的Watcher對象實體傳遞到服務端,僅僅是在客戶端請求中使用boolean類型屬性進行了標記。
四、watcher event異步發送watcher的通知事件從server發送到client是異步的,這就存在一個問題,不一樣的客戶端和服務器之間經過socket進行通訊,因爲網絡延遲或其餘因素致使客戶端在不通的時刻監聽到事件,因爲Zookeeper自己提供了ordering guarantee,即客戶端監聽事件後,纔會感知它所監視znode發生了變化。因此咱們使用Zookeeper不能指望可以監控到節點每次的變化。Zookeeper只能保證最終的一致性,而沒法保證強一致性。
五、註冊watcher getData、exists、getChildren
六、觸發watcher create、delete、setData
七、當一個客戶端鏈接到一個新的服務器上時,watch將會被以任意會話事件觸發。當與一個服務器失去鏈接的時候,是沒法接收到watch的。而當client從新鏈接時,若是須要的話,全部先前註冊過的watch,都會被從新註冊。一般這是徹底透明的。只有在一個特殊狀況下,watch可能會丟失:對於一個未建立的znode的exist watch,若是在客戶端斷開鏈接期間被建立了,而且隨後在客戶端鏈接上以前又刪除了,這種狀況下,這個watch事件可能會被丟失。
一、調用getData()/getChildren()/exist()三個API,傳入Watcher對象
二、標記請求request,封裝Watcher到WatchRegistration
三、封裝成Packet對象,發服務端發送request
四、收到服務端響應後,將Watcher註冊到ZKWatcherManager中進行管理
五、請求返回,完成註冊。
一、服務端接收Watcher並存儲
接收到客戶端請求,處理請求判斷是否須要註冊Watcher,須要的話將數據節點的節點路徑和ServerCnxn(ServerCnxn表明一個客戶端和服務端的鏈接,實現了Watcher的process接口,此時能夠當作一個Watcher對象)存儲在WatcherManager的WatchTable和watch2Paths中去。
二、Watcher觸發
以服務端接收到 setData() 事務請求觸發NodeDataChanged事件爲例:
2.1 封裝WatchedEvent
將通知狀態(SyncConnected)、事件類型(NodeDataChanged)以及節點路徑封裝成一個WatchedEvent對象
2.2 查詢Watcher
從WatchTable中根據節點路徑查找Watcher
2.3 沒找到;說明沒有客戶端在該數據節點上註冊過Watcher
2.4 找到;提取並從WatchTable和Watch2Paths中刪除對應Watcher(從這裏能夠看出Watcher在服務端是一次性的,觸發一次就失效了)
三、調用process方法來觸發Watcher
這裏process主要就是經過ServerCnxn對應的TCP鏈接發送Watcher事件通知。
客戶端SendThread線程接收事件通知,交由EventThread線程回調Watcher。客戶端的Watcher機制一樣是一次性的,一旦被觸發後,該Watcher就失效了。
目前在Linux/Unix文件系統中使用,也是使用最普遍的權限控制方式。是一種粗粒度的文件系統權限控制模式。
包括三個方面:
權限模式(Scheme)
一、IP:從IP地址粒度進行權限控制
二、Digest:最經常使用,用相似於 username:password 的權限標識來進行權限配置,便於區分不一樣應用來進行權限控制
三、World:最開放的權限控制方式,是一種特殊的digest模式,只有一個權限標識「world:anyone」
四、Super:超級用戶
受權對象
受權對象指的是權限賦予的用戶或一個指定實體,例如IP地址或是機器燈。
權限 Permission
一、CREATE:數據節點建立權限,容許受權對象在該Znode下建立子節點
二、DELETE:子節點刪除權限,容許受權對象刪除該數據節點的子節點
三、READ:數據節點的讀取權限,容許受權對象訪問該數據節點並讀取其數據內容或子節點列表等
四、WRITE:數據節點更新權限,容許受權對象對該數據節點進行更新操做
五、ADMIN:數據節點管理權限,容許受權對象對該數據節點進行ACL相關設置操做
3.2.0版本後,添加了 Chroot特性,該特性容許每一個客戶端爲本身設置一個命名空間。若是一個客戶端設置了Chroot,那麼該客戶端對服務器的任何操做,都將會被限制在其本身的命名空間下。
經過設置Chroot,可以將一個客戶端應用於Zookeeper服務端的一顆子樹相對應,在那些多個應用公用一個Zookeeper進羣的場景下,對實現不一樣應用間的相互隔離很是有幫助。
分桶策略:將相似的會話放在同一區塊中進行管理,以便於Zookeeper對會話進行不一樣區塊的隔離處理以及同一區塊的統一處理。
分配原則:每一個會話的「下次超時時間點」(ExpirationTime)
計算公式:
ExpirationTime_ = currentTime + sessionTimeout ExpirationTime = (ExpirationTime_ / ExpirationInrerval + 1) * ExpirationInterval , ExpirationInterval 是指 Zookeeper 會話超時檢查時間間隔,默認 tickTime
一、事務請求的惟一調度和處理者,保證集羣事務處理的順序性
二、集羣內部各服務的調度者
一、處理客戶端的非事務請求,轉發事務請求給Leader服務器
二、參與事務請求Proposal的投票
三、參與Leader選舉投票
一、3.0版本之後引入的一個服務器角色,在不影響集羣事務處理能力的基礎上提高集羣的非事務處理能力
二、處理客戶端的非事務請求,轉發事務請求給Leader服務器
三、不參與任何形式的投票
服務器具備四種狀態,分別是LOOKING、FOLLOWING、LEADING、OBSERVING。
一、LOOKING:尋找Leader狀態。當服務器處於該狀態時,它會認爲當前集羣中沒有Leader,所以須要進入Leader選舉狀態。
二、FOLLOWING:跟隨者狀態。代表當前服務器角色是Follower。
三、LEADING:領導者狀態。代表當前服務器角色是Leader。
四、OBSERVING:觀察者狀態。代表當前服務器角色是Observer。
整個集羣完成Leader選舉以後,Learner(Follower和Observer的統稱)迴向Leader服務器進行註冊。當Learner服務器想Leader服務器完成註冊後,進入數據同步環節。
數據同步流程:(均以消息傳遞的方式進行)
Learner向Learder註冊
數據同步
同步確認
Zookeeper的數據同步一般分爲四類:
一、直接差別化同步(DIFF同步)
二、先回滾再差別化同步(TRUNC+DIFF同步)
三、僅回滾同步(TRUNC同步)
四、全量同步(SNAP同步)
在進行數據同步前,Leader服務器會完成數據同步初始化:
peerLastZxid:
從learner服務器註冊時發送的ACKEPOCH消息中提取lastZxid(該Learner服務器最後處理的ZXID)
minCommittedLog:
Leader服務器Proposal緩存隊列committedLog中最小ZXID
maxCommittedLog:
Leader服務器Proposal緩存隊列committedLog中最大ZXID
場景:peerLastZxid介於minCommittedLog和maxCommittedLog之間
場景:當新的Leader服務器發現某個Learner服務器包含了一條本身沒有的事務記錄,那麼就須要讓該Learner服務器進行事務回滾--回滾到Leader服務器上存在的,同時也是最接近於peerLastZxid的ZXID
場景:peerLastZxid 大於 maxCommittedLog
場景一:peerLastZxid 小於 minCommittedLog
場景二:Leader服務器上沒有Proposal緩存隊列且peerLastZxid不等於lastProcessZxid
zookeeper採用了全局遞增的事務Id來標識,全部的proposal(提議)都在被提出的時候加上了zxid,zxid其實是一個64位的數字,高32位是epoch(時期; 紀元; 世; 新時代)用來標識leader週期,若是有新的leader產生出來,epoch會自增,低32位用來遞增計數。當新產生proposal的時候,會依據數據庫的兩階段過程,首先會向其餘的server發出事務執行請求,若是超過半數的機器都能執行而且可以成功,那麼就會開始執行。
在分佈式環境中,有些業務邏輯只須要集羣中的某一臺機器進行執行,其餘的機器能夠共享這個結果,這樣能夠大大減小重複計算,提升性能,因而就須要進行leader選舉。
Zookeeper自己也是集羣,推薦配置很多於3個服務器。Zookeeper自身也要保證當一個節點宕機時,其餘節點會繼續提供服務。
若是是一個Follower宕機,還有2臺服務器提供訪問,由於Zookeeper上的數據是有多個副本的,數據並不會丟失;
若是是一個Leader宕機,Zookeeper會選舉出新的Leader。
ZK集羣的機制是隻要超過半數的節點正常,集羣就能正常提供服務。只有在ZK節點掛得太多,只剩一半或不到一半節點能工做,集羣才失效。
因此
3個節點的cluster能夠掛掉1個節點(leader能夠獲得2票>1.5)
2個節點的cluster就不能掛掉任何1個節點了(leader能夠獲得1票<=1)
zk的負載均衡是能夠調控,nginx只是能調權重,其餘須要可控的都須要本身寫插件;可是nginx的吞吐量比zk大不少,應該說按業務選擇用哪一種方式。
部署模式:單機模式、僞集羣模式、集羣模式。
集羣規則爲2N+1臺,N>0,即3臺。
其實就是水平擴容了,Zookeeper在這方面不太好。兩種方式:
所有重啓:關閉全部Zookeeper服務,修改配置以後啓動。不影響以前客戶端的會話。
逐個重啓:在過半存活便可用的原則下,一臺機器重啓不影響整個集羣對外提供服務。這是比較經常使用的方式。
3.5版本開始支持動態擴容。
不是。官方聲明:一個Watch事件是一個一次性的觸發器,當被設置了Watch的數據發生了改變的時候,則服務器將這個改變發送給設置了Watch的客戶端,以便通知它們。
爲何不是永久的,舉個例子,若是服務端變更頻繁,而監聽的客戶端不少狀況下,每次變更都要通知到全部的客戶端,給網絡和服務器形成很大壓力。
通常是客戶端執行getData(「/節點A」,true),若是節點A發生了變動或刪除,客戶端會獲得它的watch事件,可是在以後節點A又發生了變動,而客戶端又沒有設置watch事件,就再也不給客戶端發送。
在實際應用中,不少狀況下,咱們的客戶端不須要知道服務端的每一次變更,我只要最新的數據便可。
java客戶端:zk自帶的zkclient及Apache開源的Curator。
chubby是google的,徹底實現paxos算法,不開源。zookeeper是chubby的開源實現,使用zab協議,paxos算法的變種。
經常使用命令:ls get set create delete等。
相同點:
一、二者都存在一個相似於Leader進程的角色,由其負責協調多個Follower進程的運行
二、Leader進程都會等待超過半數的Follower作出正確的反饋後,纔會將一個提案進行提交
三、ZAB協議中,每一個Proposal中都包含一個 epoch 值來表明當前的Leader週期,Paxos中名字爲Ballot
不一樣點:
ZAB用來構建高可用的分佈式數據主備系統(Zookeeper),Paxos是用來構建分佈式一致性狀態機系統。
Zookeeper是一個典型的發佈/訂閱模式的分佈式數據管理與協調框架,開發人員可使用它來進行分佈式數據的發佈和訂閱。
經過對Zookeeper中豐富的數據節點進行交叉使用,配合Watcher事件通知機制,能夠很是方便的構建一系列分佈式應用中年都會涉及的核心功能,如:
一、數據發佈/訂閱
二、負載均衡
三、命名服務
四、分佈式協調/通知
五、集羣管理
六、Master選舉
七、分佈式鎖
八、分佈式隊列
數據發佈/訂閱系統,即所謂的配置中心,顧名思義就是發佈者發佈數據供訂閱者進行數據訂閱。
動態獲取數據(配置信息)
實現數據(配置信息)的集中式管理和數據的動態更新
Push 模式
Pull 模式
一、數據量一般比較小
二、數據內容在運行時會發生動態更新
三、集羣中各機器共享,配置一致
如:機器列表信息、運行時開關配置、數據庫配置信息等
一、數據存儲:將數據(配置信息)存儲到Zookeeper上的一個數據節點
二、數據獲取:應用在啓動初始化節點從Zookeeper數據節點讀取數據,並在該節點上註冊一個數據變動Watcher
三、數據變動:當變動數據時,更新Zookeeper對應節點數據,Zookeeper會將數據變動通知發到各客戶端,客戶端接到通知後從新讀取變動後的數據便可。
zk的命名服務
命名服務是指經過指定的名字來獲取資源或者服務的地址,利用zk建立一個全局的路徑,這個路徑就能夠做爲一個名字,指向集羣中的集羣,提供的服務的地址,或者一個遠程的對象等等。
分佈式通知和協調
對於系統調度來講:操做人員發送通知實際是經過控制檯改變某個節點的狀態,而後zk將這些變化發送給註冊了這個節點的watcher的全部客戶端。
對於執行狀況彙報:每一個工做進程都在某個目錄下建立一個臨時節點。並攜帶工做的進度數據,這樣彙總的進程能夠監控目錄子節點的變化得到工做進度的實時的全局狀況。
zk的命名服務(文件系統)
命名服務是指經過指定的名字來獲取資源或者服務的地址,利用zk建立一個全局的路徑,便是惟一的路徑,這個路徑就能夠做爲一個名字,指向集羣中的集羣,提供的服務的地址,或者一個遠程的對象等等。
zk的配置管理(文件系統、通知機制)
程序分佈式的部署在不一樣的機器上,將程序的配置信息放在zk的znode下,當有配置發生改變時,也就是znode發生變化時,能夠經過改變zk中某個目錄節點的內容,利用watcher通知給各個客戶端,從而更改配置。
Zookeeper集羣管理(文件系統、通知機制)
所謂集羣管理無在意兩點:是否有機器退出和加入、選舉master。
對於第一點,全部機器約定在父目錄下建立臨時目錄節點,而後監聽父目錄節點的子節點變化消息。一旦有機器掛掉,該機器與 zookeeper的鏈接斷開,其所建立的臨時目錄節點被刪除,全部其餘機器都收到通知:某個兄弟目錄被刪除,因而,全部人都知道:它上船了。
新機器加入也是相似,全部機器收到通知:新兄弟目錄加入,highcount又有了,對於第二點,咱們稍微改變一下,全部機器建立臨時順序編號目錄節點,每次選取編號最小的機器做爲master就好。
Zookeeper分佈式鎖(文件系統、通知機制)
有了zookeeper的一致性文件系統,鎖的問題變得容易。鎖服務能夠分爲兩類,一個是保持獨佔,另外一個是控制時序。
對於第一類,咱們將zookeeper上的一個znode看做是一把鎖,經過createznode的方式來實現。全部客戶端都去建立 /distribute_lock 節點,最終成功建立的那個客戶端也即擁有了這把鎖。用完刪除掉本身建立的distribute_lock 節點就釋放出鎖。
對於第二類, /distribute_lock 已經預先存在,全部客戶端在它下面建立臨時順序編號目錄節點,和選master同樣,編號最小的得到鎖,用完刪除,依次方便。
Zookeeper隊列管理(文件系統、通知機制)
兩種類型的隊列:
一、同步隊列,當一個隊列的成員都聚齊時,這個隊列纔可用,不然一直等待全部成員到達。
二、隊列按照 FIFO 方式進行入隊和出隊操做。
第一類,在約定目錄下建立臨時目錄節點,監聽節點數目是不是咱們要求的數目。
第二類,和分佈式鎖服務中的控制時序場景基本原理一致,入列有編號,出列按編號。在特定的目錄下建立PERSISTENT_SEQUENTIAL節點,建立成功時Watcher通知等待的隊列,隊列刪除序列號最小的節點用以消費。此場景下Zookeeper的znode用於消息存儲,znode存儲的數據就是消息隊列中的消息內容,SEQUENTIAL序列號就是消息的編號,按序取出便可。因爲建立的節點是持久化的,因此沒必要擔憂隊列消息的丟失問題。
做者:lanqiu5ge
來源:http://t.cn/E64s1mG
搜雲庫技術團隊,歡迎廣大技術人員投稿
投稿郵箱:admin@souyunku.com
若是對本文的內容有疑問,請在文章留言區留言,謝謝。
版權申明:內容來源網絡,版權歸原創者全部。除非沒法確認,咱們都會標明做者及出處,若有侵權煩請告知咱們,咱們會當即刪除並表示歉意。謝謝!