歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> ZooKeeper如何工作?

ZooKeeper如何工作?

日期:2017/2/27 16:00:39   编辑:Linux教程
ZooKeeper是作為分布式應用建立更高層次的同步(synchronization)、配置管理 (configuration maintenance)、群組(groups)以及名稱服務(naming)。在編程上,ZooKeeper設計很簡單,所使用的數據模型風格很像文件系統的目錄樹結構,簡單來說,有點類似windows中注冊表的結構,有名稱,有樹節點,有Key(鍵)/Value(值)對的關系,可以看做一個樹形結構的數據庫,分布在不同的機器上做名稱管理。

Zookeeper分為2個部分:服務器端和客戶端,客戶端只連接到整個ZooKeeper服務的某個服務器上。客戶端使用並維護一個TCP連接,通過這個連接發送請求、接受響應、獲取觀察的事件以及發送心跳。如果這個TCP連接中斷,客戶端將嘗試連接到另外的ZooKeeper服務器。客戶端第一次連接到ZooKeeper服務時,接受這個連接的 ZooKeeper服務器會為這個客戶端建立一個會話。當這個客戶端連接到另外的服務器時,這個會話會被新的服務器重新建立。

啟動Zookeeper服務器集群環境後,多個Zookeeper服務器在工作前會選舉出一個Leader,在接下來的工作中這個被選舉出來的Leader死了,而剩下的Zookeeper服務器會知道這個Leader死掉了,在活著的Zookeeper集群中會繼續選出一個Leader,選舉出leader的目的是為了可以在分布式的環境中保證數據的一致性。如圖所示:

另外,ZooKeeper 支持watch(觀察)的概念。客戶端可以在每個znode結點上設置一個觀察。如果被觀察服務端的znode結點有變更,那麼watch就會被觸發,這個watch所屬的客戶端將接收到一個通知包被告知結點已經發生變化。若客戶端和所連接的ZooKeeper服務器斷開連接時,其他客戶端也會收到一個通知,也就說一個Zookeeper服務器端可以對於多個客戶端,當然也可以多個Zookeeper服務器端可以對於多個客戶端,如圖所示:

你還可以通過命令查看出,當前那個Zookeeper服務端的節點是Leader,哪個是Follower,如圖所示:

我通過試驗觀察到 Zookeeper的集群環境最好有3台以上的節點,如果只有2台,那麼2台當中不管那台機器down掉,將只會剩下一個leader,那麼如果有再有客戶端連接上來,將無法工作,並且剩下的leader服務器會不斷的拋出異常。內容如下:
java.net.ConnectException: Connection refused
at sun.nio.ch.Net.connect(Native Method)
at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:507)
at java.nio.channels.SocketChannel.open(SocketChannel.java:146)
at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:347)
at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectAll(QuorumCnxManager.java:381)
at org.apache.zookeeper.server.quorum.FastLeaderElection.lookForLeader(FastLeaderElection.java:674)
at org.apache.zookeeper.server.quorum.QuorumPeer.run(QuorumPeer.java:611)
2010-11-15 00:31:52,031 – INFO [QuorumPeer:/0:0:0:0:0:0:0:0:2181:FastLeaderElection@683] – Notification time out: 12800

應用實例
ZooKeeper有了上述的這些用途,讓我們設想一下,在一個分布式系統中有這這樣的一個應用:
2個任務工廠(Task Factory)一主一從,如果從的發現主的死了以後,從的就開始工作,他的工作就是向下面很多台代理(Agent)發送指令,讓每台代理(Agent)獲得不同的賬戶進行分布式並行計算,而每台代理(Agent)中將分配很多帳號,如果其中一台代理(Agent)死掉了,那麼這台死掉的代理上的賬戶就不會繼續工作了。
上述,出現了3個最主要的問題:
1.Task Factory 主/從一致性的問題
2.Task Factory 主/從心跳如何用簡單+穩定 或者2者折中的方式實現。
3.一台代理(Agent)死掉了以後,一部分的賬戶就無法繼續工作,需要通知所有在線的代理(Agent)重新分配一次帳號。

怕文字闡述的不夠清楚,畫了系統中的Task Factory和Agent的大概系統關系,如圖所示:

OK,讓我們想想ZooKeeper是不是能幫助我們去解決目前遇到的這3個最主要的問題呢?
解決思路
1. 任務工廠Task Factory都連接到ZooKeeper上,創建節點,設置對這個節點進行監控,監控方法例如:
event= new WatchedEvent(EventType.NodeDeleted, KeeperState.SyncConnected, "/TaskFactory");
這個方法的意思就是只要Task Factory與zookeeper斷開連接後,這個節點就會被自動刪除。

2.原來主的任務工廠斷開了TCP連接,這個被創建的/TaskFactory節點就不存在了,而且另外一個連接在上面的Task Factory可以立刻收到這個事件(Event),知道這個節點不存在了,也就是說主TaskFactory死了。

3.接下來另外一個活著的TaskFactory會再次創建/TaskFactory節點,並且寫入自己的ip到znode裡面,作為新的標記。

4.此時Agents也會知道主的TaskFactory不工作了,為了防止系統中大量的拋出異常,他們將會先把自己手上的事情做完,然後掛起,等待收到Zookeeper上重新創建一個/TaskFactory節點,收到 EventType.NodeCreated 類型的事件將會繼續工作。

5.原來從的TaskFactory 將自己變成一個主TaskFactory,當系統管理員啟動原來死掉的主的TaskFactory,世界又恢復平靜了。

6.如果一台代理死掉,其他代理他們將會先把自己手上的事情做完,然後掛起,向TaskFactory發送請求,TaskFactory會重新分配(sharding)帳戶到每個Agent上了,繼續工作。

上述內容,大致如圖所示:
1、Zookeeper客戶端與服務端的大致結構
服務端
Zookeeper還是屬於一個C/S的架構的應用服務,Zookeeper的服務器端分為2種運行模式:單台和集群多台的運行模式,通過conf/zoo.cfg中的配置判定你啟用的運行模式,以及在群集模式中數據同步和心跳的頻率等等。
Zookeeper集群中的Leader和Follower之間的選舉通過Paxos算法來實現的,它是一個基於消息傳遞的一致性算法,這裡講述了http://zh.wikipedia.org/zh-cn/Paxos算法,傳說中Paxos算法是分布式一致性算法中最有效的一種算法。
口水:在源代碼中的通訊部分看見了大量采用NIO和concurrent的代碼(例如:LinkedBlockingQueue/AtomicLong)。

客戶端
ZooKeeper的Client由三個主要模塊組成:
Zookeeper
Zookeeper是最主要的類,可以寫入一個或者多個Zookeeper的服務器地址,例如:"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" ,當你new Zookeeper( ….)的時候會有兩個線程被創建:SendThread和EventThread,會在Server端創建大量的Session。
WatcherManager
在Zookeeper類中還有一個WatcherManager,用來管理Watcher的,Watcher是ZK的一大特色功能,允許多個Client對一個或多個 ZNode進行監控,當ZNode有變化時能夠通知到監控這個ZNode的各個Client,管理了ZK Client綁定的所有Watcher。
ClientCnxn
在Zookeeper類中還包含了對ClientCnxn類的調用,ClientCnxn這個類管理所有對Zookeeper服務器端的網絡通訊,服務端和客戶端所有交互的數據都要調用這個類,包括給ZK Server發送Request,從ZK Server接受Response,以及從ZK Server接受Watcher Event。
Copyright © Linux教程網 All Rights Reserved