定義html
ZooKeeper是Hadoop的正式子項目,它是一個針對大型分佈式系統的可靠協調系統,提供的功能包括:配置維護、名字服務、分佈式同步、組服務等。ZooKeeper的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。node
原理算法
ZooKeeper是以Fast Paxos算法爲基礎的,paxos算法存在活鎖的問題,即當有多個proposer交錯提交時,有可能互相排斥致使沒有一個proposer能提交成功,而Fast Paxos做了一些優化,經過選舉產生一個leader,只有leader才能提交propose,具體算法可見Fast Paxos。shell
系統結構apache
在zookeeper中實現了一個相似file system系統的數據結構,好比/zookeeper/status。 每一個節點都對應於一個znode節點。Zookeeper的功能都是經過對znode的操做實現的服務器
znode 的 模式:網絡
PERSISTENT (持續的,相比於EPHEMERAL,不會隨着client session的close/expire而消失)session
PERSISTENT_SEQUENTIAL數據結構
EPHEMERAL (短暫的,生命週期依賴於client session,對應session close/expire後其znode也會消失)app
EPHEMERAL_SEQUENTIAL (SEQUENTIAL意爲順序的)
zxid (ZooKeeper Transaction Id,每次請求對應一個惟一的zxid,若是zxid a < zxid b ,則能夠保證a必定發生在b以前)。
對應zxid 有兩個
czxid
The zxid of the change that caused this znode to be created.
mzxid
The zxid of the change that last modified this znode.
Alone模式的啓動方法:
conf/zoo.cfg:
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
運行 bin/zkServer.sh start
shell客戶端鏈接:
bin/zkCli.sh -server 127.0.0.1:2181
能夠經過help打印出幫助信息
常見操控znode命令有:
get path [watch]
create [-s] [-e] path data acl
ls path [watch]
set path data [version]
delete path [version]
[zk: 127.0.0.1:2181(CONNECTED) 2] create -s /zk_test/st1 aaaa
Created /zk_test/st10000000000
[zk: 127.0.0.1:2181(CONNECTED) 3] create -s /zk_test/st1 aaaa
Created /zk_test/st10000000001
對某個znode節點 創建watch
get /zk_test/et10000000009 watch
Watches
Zookeeper 全部的讀操做—— getData() , getChildren() , 和 exists() 都 能夠設置監視(watch),監視事件能夠理解爲一次性的觸發器, 官方定義以下: a watch event is one-time trigger, sent to the client that set the watch, which occurs when the data for which the watch was set changes。對此須要做出以下理解:
(一次性觸發)One-time trigger
當設置監視的數據發生改變時,該監視事件會被髮送到客戶端,例如,若是客戶端調用了 getData("/znode1", true) 而且稍後 /znode1 節點上的數據發生了改變或者被刪除了,客戶端將會獲取到 /znode1 發生變化的監視事件,而若是 /znode1 再一次發生了變化,除非客戶端再次對 /znode1 設置監視,不然客戶端不會收到事件通知。
(發送至客戶端)Sent to the client
Zookeeper 客戶端和服務端是經過 socket 進行通訊的,因爲網絡存在故障,因此監視事件頗有可能不會成功地到達客戶端,監視事件是異步發送至監視者的,Zookeeper 自己提供了保序性(ordering guarantee):即客戶端只有首先看到了監視事件後,纔會感知到它所設置監視的 znode 發生了變化(a client will never see a change for which it has set a watch until it first sees the watch event). 網絡延遲或者其餘因素可能致使不一樣的客戶端在不一樣的時刻感知某一監視事件,但 是不一樣的客戶端所看到的一切具備一致的順序。
(被設置watch的數據)The data for which the watch was set
這意味着 znode 節點自己具備不一樣的改變方式。你也能夠想象 Zookeeper 維護了兩條監視鏈表:數據監視和子節點監視(data watches and child watches) getData() and exists() 設置數據監視,getChildren() 設置子節點監視。 或者,你也能夠想象 Zookeeper 設置的不一樣監視返回不一樣的數據,getData() 和 exists() 返回 znode 節點的相關信息,而 getChildren() 返回子節點列表。所以, setData() 會觸發設置在某一節點上所設置的數據監視(假定數據設置成功),而一次成功的 create() 操做則會出發當前節點上所設置的數據監視以及父節點的子節點監視。一次成功的 delete() 操做將會觸發當前節點的數據監視和子節點監視事件,同時也會觸發該節點父節點的child watch。
Zookeeper 中的監視是輕量級的,所以容易設置、維護和分發。當客戶端與 Zookeeper 服務器端失去聯繫時,客戶端並不會收到監視事件的通知,只有當客戶端從新鏈接後,若在必要的狀況下,之前註冊的監視會從新被註冊並觸發,對於開發人員來講 這一般是透明的。只有一種狀況會致使監視事件的丟失,即:經過 exists() 設置了某個 znode 節點的監視,可是若是某個客戶端在此 znode 節點被建立和刪除的時間間隔內與 zookeeper 服務器失去了聯繫,該客戶端即便稍後從新鏈接 zookeeper服務器後也得不到事件通知。
對於watch,zookeeper提供如下保證:
1.watch對於其餘事件、watch、異步響應是有序的。zookeeper client library保證有序分發
2.客戶端監視一個節點,老是先獲取watch事件,再發現節點的數據變化。
3.watch事件的順序對應於zookeeper服務所見的數據更新的順序。
關於watch要記住的是:
1.watch是一次性觸發的,若是獲取一個watch事件並但願獲得新變化的通知,須要從新設置watch
2.watch是一次性觸發的而且在獲取watch事件和設置新watch事件之間有延遲,因此不能可靠的觀察到節點的每一次變化。要認識到這一點。
3.watch object只觸發一次,好比,一個watch object被註冊到同一個節點的getData()和exists(),節點被刪除,僅對應於exists()的watch ojbect被調用
4.若與服務端斷開鏈接,直到重連後才能獲取watch事件。
Watch事件類型:
ZOO_CREATED_EVENT:節點建立事件,須要watch一個不存在的節點,當節點被建立時觸發,此watch經過zoo_exists()設置
ZOO_DELETED_EVENT:節點刪除事件,此watch經過zoo_exists()或zoo_get()設置
ZOO_CHANGED_EVENT:節點數據改變事件,此watch經過zoo_exists()或zoo_get()設置
ZOO_CHILD_EVENT:子節點列表改變事件,此watch經過zoo_get_children()或zoo_get_children2()設置
ZOO_SESSION_EVENT:會話失效事件,客戶端與服務端斷開或重連時觸發
ZOO_NOTWATCHING_EVENT:watch移除事件,服務端出於某些緣由再也不爲客戶端watch節點時觸發
ACL
傳統的文件系統中,ACL分爲兩個維度,一個是屬組,一個是權限,子目錄/文件默認繼承父目錄的ACL。而在Zookeeper中,node的ACL是沒有繼承關係的,是獨立控制的。Zookeeper的ACL,能夠從三個維度來理解:一是scheme; 二是user; 三是permission,一般表示爲scheme:id:permissions, 下面從這三個方面分別來介紹:
scheme: scheme對應於採用哪一種方案來進行權限管理,zookeeper實現了一個pluggable的ACL方案,能夠經過擴展scheme,來擴展ACL的機制。zookeeper-3.4.4缺省支持下面幾種scheme:
world: 它下面只有一個id, 叫anyone, world:anyone表明任何人,zookeeper中對全部人有權限的結點就是屬於world:anyone的
auth: 它不須要id, 只要是經過authentication的user都有權限(zookeeper支持經過kerberos來進行authencation, 也支持username/password形式的authentication)
digest: 它對應的id爲username:BASE64(SHA1(password)),它須要先經過username:password形式的authentication
ip: 它對應的id爲客戶機的IP地址,設置的時候能夠設置一個ip段,好比ip:192.168.1.0/16, 表示匹配前16個bit的IP段
super: 在這種scheme狀況下,對應的id擁有超級權限,能夠作任何事情(cdrwa)
另外,zookeeper-3.4.4的代碼中還提供了對sasl的支持,不過缺省是沒有開啓的,須要配置才能啓用,具體怎麼配置在下文中介紹。
sasl: sasl的對應的id,是一個經過sasl authentication用戶的id,zookeeper-3.4.4中的sasl authentication是經過kerberos來實現的,也就是說用戶只有經過了kerberos認證,才能訪問它有權限的node.
id: id與scheme是緊密相關的,具體的狀況在上面介紹scheme的過程都已介紹,這裏再也不贅述。
permission: zookeeper目前支持下面一些權限:
CREATE(c): 建立權限,能夠在在當前node下建立child node
DELETE(d): 刪除權限,能夠刪除當前的node
READ(r): 讀權限,能夠獲取當前node的數據,能夠list當前node全部的child nodes
WRITE(w): 寫權限,能夠向當前node寫數據
ADMIN(a): 管理權限,能夠設置當前node的permission
zookeeper使用事例:
1. 配置項管理
分佈式系統中,常常會有多個節點共享一份配置信息,而且配置信息可能動態的發生變化,此時須要節點能在配置變化時動態加載,經過zookeeper可很方便的完成。將配置信息存儲在zookeeper的某個節點C上(可能包含不少配置子項),進程啓動時先鏈接zookeeper獲取C上的配置信息並註冊watch,當配置信息發生變化時會獲得通知,此時進程從新加載配置。
2. 主從配合
分佈式系統中,多個進程可能須要協做,某個進程在啓動時須要知道其餘進程的一些信息,而這些信息可能會動態變化。如某系統中,包含一個master進程和多個worker進程,worker在啓動時必須鏈接知道master的運行的一些信息(如ip:port,狀態等),而master的運行由調度器完成,可能動態變化,經過zookeeper可完成這類需求。在zookeeper上建立一個節點R,當master啓動時,將其運行信息寫入R節點,當worker啓動時,讀取R的信息並設置watch,若是R中有信息,則讀取並啓動;若是沒有,當master向R寫入信息後,worker會被通知,此時讀取信息而且啓動worker;另外,能夠將R設爲Ephemeral並註冊deletewatch時間,當R不存在時,全部的進程退出。
3. 組管理
組管理在分佈式系統中很常見,如某個分佈式存儲系統,包含多個存儲節點,這多個存儲節點構成一個group,合理管理group是系統運行的關鍵,如監控並處理group中節點加入(擴展性)和退出(容錯)事件,經過zookeeper也可方便實現組管理功能。用一個節點G表明group,系統在group上設置watch,當有節點加入時,在G下建立一個臨時子節點,當節點退出時,臨時子節點也會被刪除,系統只須要根據相應的事件類型進行處理便可。
4. 分佈式鎖
解決方案依然很簡單,須要加鎖的進程先嚐試在zookeeper上建立一個臨時節點L,若是建立成功則加鎖成功,若是不成功(已存在)則在該節點上設置watch。進程經過刪除L來解鎖(當進程意外終止,L也會被刪除,不會形成死鎖),當L被刪除時,其它等待鎖的進程會獲得通知,此時這些進程再次建立L來得到鎖。
上面的方案,當競爭鎖的進程比較多時,解鎖時會引發Herd Effect,可對加鎖規則進行限制,如按進程嘗試加鎖的順序來分配鎖。在zookeeper上,每一個加鎖的進程建立一個帶SEQUENTIAL標誌的臨時節點,每次讓序號最小的節點得到鎖,這樣每一個節點只須要watch它前面節點的狀態便可,當其前面節點被刪除時,其將被通知,並得到鎖。
5. 分佈式Barrier
Barrier是一種控制和協調多個任務觸發次序的機制,簡單說來就是搞個閘門把欲執行的任務給攔住,等全部任務都處於能夠執行的狀態時,才放開閘門。
是用一個Node做爲Barrer的實體,須要被Barrer的任務經過調用exists()檢測這個Node的存在,當須要打開Barrier的時候,刪掉這個Node,ZooKeeper的watch機制會通知到各個任務能夠開始執行。
6. 分佈式 Queue
與 Barrier相似 分佈式環境中 實現Queue也須要高一致性作保障, ZooKeeper提供了一個種簡單的方式, ZooKeeper經過一個Node來維護Queue的實體,用其children來存儲Queue的內容,而且 ZooKeeper的create方法中提供了順序遞增的模式,會自動地在name後面加上一個遞增的數字來插入新元素。能夠用其 children來構建一個queue的數據結構,offer的時候使用create,take的時候按照children的順序刪除第一個便可。 ZooKeeper保障了各個server上數據是一致的,所以也就實現了一個 分佈式 Queue。
Curator
Curator是Netflix開源的一套ZooKeeper客戶端框架.
Curator主要解決了三類問題:
封裝ZooKeeper client與ZooKeeper server之間的鏈接處理;
提供了一套Fluent風格的操做API;
提供ZooKeeper各類應用場景(recipe, 好比共享鎖服務, 集羣領導選舉機制)的抽象封裝.
CuratorFramework zkClient = CuratorFrameworkFactory .builder() .connectString(zkQuorum) .retryPolicy( new RetryNTimes(zkRetryTimes, zkRetrySleepInterval))
.build(); zkClient.start(); zkClient.create().creatingParentsIfNeeded() .forPath(shardZkPath, null); byte[] shardZkData = zkClient.getData().forPath( shardZkPath);
參考資料:
整體:
http://agapple.iteye.com/blog/1111377
http://blog.csdn.net/cutesource/article/details/5822459
http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html
http://okwangxing.iteye.com/blog/598548
Acl:
http://www.wuzesheng.com/?p=2438
curator