Zookeeper基本使用(轉)

1、Zookeeper架構java

雲計算愈來愈流行的今天,單一機器處理能力已經不能知足咱們的需求,不得不採用大量的服務集羣。服務集羣對外提供服務的過程當中,有不少的配置須要隨時更新,服務間須要協調工做,這些信息如何推送到各個節點?而且保證信息的一致性和可靠性?node

衆所周知,分佈式協調服務很難正確無誤的實現,它們很容易在競爭條件和死鎖上犯錯誤。如何在這方面節省力氣?Zookeeper是一個不錯的選擇。 Zookeeper背後的動機就是解除分佈式應用在實現協調服務上的痛苦。本文在介紹Zookeeper的基本理論基礎上,用Zookeeper實現了一 個配置管理中心,利用Zookeeper將配置信息分發到各個服務節點上,並保證信息的正確性和一致性。linux

Zookeeper是什麼?

引用官方的說法:「Zookeeper是一個高性能,分佈式的,開源分佈式應用協調服務。它提供了簡單原始的功能,分佈式應用能夠基於它實現更高級 的服務,好比同步,配置管理,集羣管理,名空間。它被設計爲易於編程,使用文件系統目錄樹做爲數據模型。服務端跑在java上,提供java和C的客戶端 API」。redis

Zookeeper整體結構

Zookeeper服務自身組成一個集羣(2n+1個服務容許n個失效)。Zookeeper服務有兩個角色,一個是leader,負責寫服務和數據同步,剩下的是follower,提供讀服務,leader失效後會在follower中從新選舉新的leader。數據庫

Zookeeper邏輯圖以下,apache

  1. 客戶端能夠鏈接到每一個server,每一個server的數據徹底相同。
  2. 每一個follower都和leader有鏈接,接受leader的數據更新操做。
  3. Server記錄事務日誌和快照到持久存儲。
  4. 大多數server可用,總體服務就可用。

Zookeeper 特色

  • 順序一致性:按照客戶端發送請求的順序更新數據。
  • 原子性:更新要麼成功,要麼失敗,不會出現部分更新。
  • 單一性 :不管客戶端鏈接哪一個server,都會看到同一個視圖。
  • 可靠性:一旦數據更新成功,將一直保持,直到新的更新。
  • 及時性:客戶端會在一個肯定的時間內獲得最新的數據。

2、Zookeeper數據模型編程

ZooKeeper的數據結構, 與普通的文件系統極爲相似. 見下圖:centos

圖片引用自developerworksapi

圖中的每一個節點稱爲一個znode. 每一個znode由3部分組成:緩存

  • stat. 此爲狀態信息, 描述該znode的版本, 權限等信息.
  • data. 與該znode關聯的數據.
  • children. 該znode下的子節點.

3、Zookeeper應用場景

一、統一命名服務(Name Service)

分佈式應用中,一般須要有一套完整的命名規則,既可以產生惟一的名稱又便於人識別和記住,一般狀況下用樹形的名稱結構是一個理想的選擇,樹形的名稱結構是一個有層次的目錄結構,既對人友好又不會重複。說到這裏你可能想到了 JNDI,沒錯 Zookeeper 的 Name Service 與 JNDI 可以完成的功能是差很少的,它們都是將有層次的目錄結構關聯到必定資源上,可是 Zookeeper 的 Name Service 更加是普遍意義上的關聯,也許你並不須要將名稱關聯到特定資源上,你可能只須要一個不會重複名稱,就像數據庫中產生一個惟一的數字主鍵同樣。 
Name Service 是 Zookeeper 內置的功能,你只要調用 Zookeeper 的 API 就能實現。如調用 create 接口就能夠很容易建立一個目錄節點。 
以上摘自IMB Bluemix的分佈式服務框架 Zookeeper – 管理分佈式環境中的數據文章中,我做個總結: 
1)提供相似JNDI的服務,這也是Zookeeper的基礎,整個Zookeeper的功能就是圍繞樹形結構的內容進行展開的 
2)提供臨時類型(EPHEMERAL)的目錄 
3)提供順序自動編號類型(SEQUENTIAL)的目錄 
關於2)、3)點會在後面做詳細介紹,集羣管理、共享鎖就是基於以上特性進行實現的

二、統一配置管理(Configuration Management)

配置的管理在分佈式應用環境中很常見,例如同一個應用系統須要多臺 PC Server 運行,可是它們運行的應用系統的某些配置項是相同的,若是要修改這些相同的配置項,那麼就必須同時修改每臺運行這個應用系統的 PC Server,這樣很是麻煩並且容易出錯。 
像這樣的配置信息徹底能夠交給 Zookeeper 來管理,將配置信息保存在 Zookeeper 的某個目錄節點中,而後將全部須要修改的應用機器監控配置信息的狀態,一旦配置信息發生變化,每臺應用機器就會收到 Zookeeper 的通知,而後從 Zookeeper 獲取新的配置信息應用到系統中。 
以上摘自IMB Bluemix的分佈式服務框架 Zookeeper – 管理分佈式環境中的數據文章中。 
在咱們使用JVM內存進行數據緩存的場景下,能夠採用ZK的這種方式進行數據更新。有人說能夠直接使用memcached、redis進行統一配置管理,這樣直接修改redis中的數據就能夠了,在對緩存數據的訪問量不大的前提下,該設計是沒有問題的,當數據訪問量極大的時候該設計存在一個問題,就是頻繁的訪問memcached、redis形成大量的網絡開銷,進而影響系統性能。所以將數據緩存至JVM更合適一些。這裏只是舉了一個簡單的例子,關於緩存的使用以後寫一篇文章進行詳細的分析。

三、集羣管理(Cluster Management)

Zookeeper 可以很容易的實現集羣管理的功能,若有多臺 Server 組成一個服務集羣,那麼必需要一個「總管」知道當前集羣中每臺機器的服務狀態,一旦有機器不能提供服務,集羣中其它集羣必須知道,從而作出調整從新分配服務策略。一樣當增長集羣的服務能力時,就會增長一臺或多臺 Server,一樣也必須讓「總管」知道。 
Zookeeper 不只可以幫你維護當前的集羣中機器的服務狀態,並且可以幫你選出一個「總管」,讓這個總管來管理集羣,這就是 Zookeeper 的另外一個功能 Leader Election。 
它們的實現方式都是在 Zookeeper 上建立一個 EPHEMERAL 類型的目錄節點,而後每一個 Server 在它們建立目錄節點的父目錄節點上調用 getChildren(String path, boolean watch) 方法並設置 watch 爲 true,因爲是 EPHEMERAL 目錄節點,當建立它的 Server 死去,這個目錄節點也隨之被刪除,因此 Children 將會變化,這時 getChildren上的 Watch 將會被調用,因此其它 Server 就知道已經有某臺 Server 死去了。新增 Server 也是一樣的原理。 
Zookeeper 如何實現 Leader Election,也就是選出一個 Master Server。和前面的同樣每臺 Server 建立一個 EPHEMERAL 目錄節點,不一樣的是它仍是一個 SEQUENTIAL 目錄節點,因此它是個 EPHEMERAL_SEQUENTIAL 目錄節點。之因此它是 EPHEMERAL_SEQUENTIAL 目錄節點,是由於咱們能夠給每臺 Server 編號,咱們能夠選擇當前是最小編號的 Server 爲 Master,假如這個最小編號的 Server 死去,因爲是 EPHEMERAL 節點,死去的 Server 對應的節點也被刪除,因此當前的節點列表中又出現一個最小編號的節點,咱們就選擇這個節點爲當前 Master。這樣就實現了動態選擇 Master,避免了傳統意義上單 Master 容易出現單點故障的問題。 
以上摘自IMB Bluemix的分佈式服務框架 Zookeeper – 管理分佈式環境中的數據文章中。

四、共享鎖(Locks)

共享鎖在同一個進程中很容易實現,可是在跨進程或者在不一樣 Server 之間就很差實現了。Zookeeper 卻很容易實現這個功能,實現方式也是須要得到鎖的 Server 建立一個 EPHEMERAL_SEQUENTIAL 目錄節點,而後調用 getChildren方法獲取當前的目錄節點列表中最小的目錄節點是否是就是本身建立的目錄節點,若是正是本身建立的,那麼它就得到了這個鎖,若是不是那麼它就調用 exists(String path, boolean watch) 方法並監控 Zookeeper 上目錄節點列表的變化,一直到本身建立的節點是列表中最小編號的目錄節點,從而得到鎖,釋放鎖很簡單,只要刪除前面它本身所建立的目錄節點就好了。 
以上摘自IMB Bluemix的分佈式服務框架 Zookeeper – 管理分佈式環境中的數據文章中。

5、隊列管理(Queue Management)

Zookeeper 能夠處理兩種類型的隊列: 
當一個隊列的成員都聚齊時,這個隊列纔可用,不然一直等待全部成員到達,這種是同步隊列。 
隊列按照 FIFO 方式進行入隊和出隊操做,例如實現生產者和消費者模型。 
1)同步隊列用 Zookeeper 實現的實現思路以下: 
建立一個父目錄 /synchronizing,每一個成員都監控標誌(Set Watch)位目錄 /synchronizing/start 是否存在,而後每一個成員都加入這個隊列,加入隊列的方式就是建立 /synchronizing/member_i 的臨時目錄節點,而後每一個成員獲取 / synchronizing 目錄的全部目錄節點,也就是 member_i。判斷 i 的值是否已是成員的個數,若是小於成員個數等待 /synchronizing/start 的出現,若是已經相等就建立 /synchronizing/start。 
2)FIFO 隊列用 Zookeeper 實現思路以下: 
實現的思路也很是簡單,就是在特定的目錄下建立 SEQUENTIAL 類型的子目錄 /queue_i,這樣就能保證全部成員加入隊列時都是有編號的,出隊列時經過 getChildren( ) 方法能夠返回當前全部的隊列中的元素,而後消費其中最小的一個,這樣就能保證 FIFO。 
以上摘自IMB Bluemix的分佈式服務框架 Zookeeper – 管理分佈式環境中的數據文章中。

 

4、Zookeeper安裝與使用

安裝環境爲centos6.5

172.16.80.177

172.16.80.178

1. 配置機器名。

vi /etc/hosts
172.16.80.177 zookeeper1
172.16.80.178 zookeeper2

2. 安裝JDK並配置環境變量(JAVA_HOME、CLASSPATH、PATH)。

三、下載Zookeeper安裝包

https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/

我下載3.4.8版本

 

4. 安裝並配置(兩臺機器上都要作一樣的配置)。

將zookeeper-3.4.8.tar.gz放到root目錄下

mkdir -p /opt/app
tar zxvf zookeeper-3.4.8.tar.gz -C /opt/app/ cd /opt/app/zookeeper-3.4.8/ mkdir data/ logs/
cd /conf
mv zoo_sample.cfg zoo.cfg vi zoo.cfg # 集羣每臺機器的zoo.cfg配置必須一致。
複製代碼
tickTime=2000
dataDir=/opt/app/zookeeper-3.4.8/data/
dataLogDir=/opt/app/zookeeper-3.4.8/logs/
clientPort=2181
initLimit=5
syncLimit=2
server.1=zookeeper1:2888:3888 # 每臺機器都要感知集羣的機器組成,配置格式爲「server.id=host:port:port」。id範圍1~255。
server.2=zookeeper2:2888:3888
複製代碼
# 在data目錄建立myid文件。根據zoo.cfg配置,id應與機器對應。如zookeeper1的id爲1,zookeeper2的id爲2.
echo 1 > data/myid
echo 2 > data/myid

echo 1是在機器1上執行,echo 2是要在機器2上執行

5. 啓動、關閉。

/opt/app/zookeeper-3.4.8/bin/zkServer.sh start
/opt/app/zookeeper-3.4.8/bin/zkServer.sh stop
/opt/app/zookeeper-3.4.8/bin/zkServer.sh status
[root@host-172-16-80-178 bin]# /opt/app/zookeeper-3.4.8/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/app/zookeeper-3.4.8/bin/../conf/zoo.cfg
Mode: leader
[root@host-172-16-80-177 zookeeper-3.4.8]# /opt/app/zookeeper-3.4.8/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/app/zookeeper-3.4.8/bin/../conf/zoo.cfg
Mode: follower

六、鏈接zookeeper

[root@host-172-16-80-177 zookeeper-3.4.8]# /opt/app/zookeeper-3.4.8/bin/zkCli.sh -server zookeeper2:2181
Connecting to zookeeper1:2181
2017-10-19 04:29:07,456 [myid:] - INFO  [main:Environment@100] - Client environment:zookeeper.version=3.4.8--1, built on 02/06/2016 03:18 GMT
2017-10-19 04:29:07,460 [myid:] - INFO  [main:Environment@100] - Client environment:host.name=<NA>
2017-10-19 04:29:07,460 [myid:] - INFO  [main:Environment@100] - Client environment:java.version=1.7.0_80
2017-10-19 04:29:07,463 [myid:] - INFO  [main:Environment@100] - Client environment:java.vendor=Oracle Corporation
2017-10-19 04:29:07,463 [myid:] - INFO  [main:Environment@100] - Client environment:java.home=/usr/java/jdk1.7.0_80/jre
2017-10-19 04:29:07,463 [myid:] - INFO  [main:Environment@100] - Client environment:java.class.path=/opt/app/zookeeper-3.4.8/bin/../build/classes:/opt/app/zookeeper-3.4.8/bin/../build/lib/*.jar:/opt/app/zookeeper-3.4.8/bin/../lib/slf4j-log4j12-1.6.1.jar:/opt/app/zookeeper-3.4.8/bin/../lib/slf4j-api-1.6.1.jar:/opt/app/zookeeper-3.4.8/bin/../lib/netty-3.7.0.Final.jar:/opt/app/zookeeper-3.4.8/bin/../lib/log4j-1.2.16.jar:/opt/app/zookeeper-3.4.8/bin/../lib/jline-0.9.94.jar:/opt/app/zookeeper-3.4.8/bin/../zookeeper-3.4.8.jar:/opt/app/zookeeper-3.4.8/bin/../src/java/lib/*.jar:/opt/app/zookeeper-3.4.8/bin/../conf:
2017-10-19 04:29:07,463 [myid:] - INFO  [main:Environment@100] - Client environment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
2017-10-19 04:29:07,463 [myid:] - INFO  [main:Environment@100] - Client environment:java.io.tmpdir=/tmp
2017-10-19 04:29:07,463 [myid:] - INFO  [main:Environment@100] - Client environment:java.compiler=<NA>
2017-10-19 04:29:07,464 [myid:] - INFO  [main:Environment@100] - Client environment:os.name=Linux
2017-10-19 04:29:07,464 [myid:] - INFO  [main:Environment@100] - Client environment:os.arch=amd64
2017-10-19 04:29:07,464 [myid:] - INFO  [main:Environment@100] - Client environment:os.version=2.6.32-573.el6.x86_64
2017-10-19 04:29:07,464 [myid:] - INFO  [main:Environment@100] - Client environment:user.name=root
2017-10-19 04:29:07,464 [myid:] - INFO  [main:Environment@100] - Client environment:user.home=/root
2017-10-19 04:29:07,464 [myid:] - INFO  [main:Environment@100] - Client environment:user.dir=/opt/app/zookeeper-3.4.8
2017-10-19 04:29:07,466 [myid:] - INFO  [main:ZooKeeper@438] - Initiating client connection, connectString=zookeeper1:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@594b7042
Welcome to ZooKeeper!
2017-10-19 04:29:07,501 [myid:] - INFO  [main-SendThread(zookeeper1:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server zookeeper1/172.16.80.177:2181. Will not attempt to authenticate using SASL (unknown error)
2017-10-19 04:29:07,515 [myid:] - INFO  [main-SendThread(zookeeper1:2181):ClientCnxn$SendThread@876] - Socket connection established to zookeeper1/172.16.80.177:2181, initiating session
JLine support is enabled
2017-10-19 04:29:07,552 [myid:] - INFO  [main-SendThread(zookeeper1:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server zookeeper1/172.16.80.177:2181, sessionid = 0x15f33b62ee10001, negotiated timeout = 30000

WATCHER::

WatchedEvent state:SyncConnected type:None path:null

 

複製代碼

[zk: zookeeper1:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: zookeeper1:2181(CONNECTED) 1] create /helloworld 123
Created /helloworld
[zk: zookeeper1:2181(CONNECTED) 2] ls /
[helloworld, zookeeper]
[zk: zookeeper1:2181(CONNECTED) 3] quit
Quitting...
2017-10-19 04:33:01,671 [myid:] - INFO [main:ZooKeeper@684] - Session: 0x15f33b62ee10002 closed
2017-10-19 04:33:01,675 [myid:] - INFO [main-EventThread:ClientCnxn$EventThread@519] - EventThread shut down for session: 0x15f33b62ee10002

複製代碼
/opt/app/zookeeper-3.4.8/bin/zkCli.sh -server zookeeper2:2181
[zk: zookeeper1:2181(CONNECTED) 0] ls /
[helloworld, zookeeper]
[zk: zookeeper1:2181(CONNECTED) 1]  get /helloworld
123
cZxid = 0x100000005
ctime = Thu Oct 19 04:32:43 EDT 2017
mZxid = 0x100000005
mtime = Thu Oct 19 04:32:43 EDT 2017
pZxid = 0x100000005
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
[zk: zookeeper1:2181(CONNECTED) 2] 

 

help命令

顯示客戶所支持的全部命令,如:

ZooKeeper -server host:port cmd args

       connecthost:port

       getpath [watch]

       lspath [watch]

       setpath data [version]

       rmrpath

       delquota[-n|-b] path

       quit

       printwatcheson|off

       create[-s] [-e] path data acl

       statpath [watch]

       close

       ls2path [watch]

       history

       listquotapath

       setAclpath acl

       getAclpath

       syncpath

       redocmdno

       addauthscheme auth

       deletepath [version]

       setquota-n|-b val path

connect命令

鏈接zk服務端,與close命令配合使用能夠鏈接或者斷開zk服務端。

如connect 127.0.0.1:2181

get命令

獲取節點信息,注意節點的路徑皆爲絕對路徑,也就是說必要要從/(根路徑)開始。

如get /

hello world

cZxid = 0x0

ctime = Thu Jan 01 08:00:00 CST 1970

mZxid = 0x5

mtime = Thu Apr 27 15:09:00 CST 2017

pZxid = 0xc

cversion = 1

dataVersion = 2

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 11

numChildren = 1

詳解:

hello world爲節點數據信息

cZxid節點建立時的zxid

ctime節點建立時間

mZxid節點最近一次更新時的zxid

mtime節點最近一次更新的時間

cversion子節點數據更新次數

dataVersion本節點數據更新次數

aclVersion節點ACL(受權信息)的更新次數

ephemeralOwner若是該節點爲臨時節點,ephemeralOwner值表示與該節點綁定的session id. 若是該節點不是臨時節點,ephemeralOwner值爲0

dataLength節點數據長度,本例中爲hello world的長度

numChildren子節點個數

ls命令

獲取路徑下的節點信息,注意此路徑爲絕對路徑,相似於linux的ls命令。

如ls /zookeeper

set命令

設置節點的數據。

如set /zookeeper "hello world"

rmr命令

刪除節點命令,此命令與delete命令不一樣的是delete不可刪除有子節點的節點,可是rmr命令能夠刪除,注意路徑爲絕對路徑。

如rmr /zookeeper/znode

delquota命令

刪除配額,-n爲子節點個數,-b爲節點數據長度。

如delquota –n 2,請參見listquota和setquota命令。

quit命令

退出。

printwatches命令

設置和顯示監視狀態,on或者off。

如printwatches on

create命令

建立節點,其中-s爲順序充點,-e臨時節點。

如create /zookeeper/node1"test_create" world:anyone:cdrwa

其中acl處,請參見getAcl和setAcl命令。

stat命令

查看節點狀態信息。如stat /

cZxid = 0x0

ctime = Thu Jan 01 08:00:00 CST 1970

mZxid = 0x1f

mtime = Thu Apr 27 16:05:14 CST 2017

pZxid = 0xc

cversion = 1

dataVersion = 3

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 5

numChildren = 1

與get命令大致相同,請參見get命令。

close命令

斷開客戶端與服務端的鏈接。

ls2命令

ls2爲ls命令的擴展,比ls命令多輸出本節點信息。

如 ls /zookeeper

history命令

列出最近的歷史命令。

如history

0 - ls /

1 - ls /

2 - ls2 /

3 - history

4 - listquota /zookeeper

5 – history

基本格式爲:命令ID-命令,能夠與redo命令配合使用。

 

listquota命令

顯示配額。

如listquota /zookeeper

absolute path is/zookeeper/quota/zookeeper/zookeeper_limits

Output quota for /zookeepercount=2,bytes=-1

解釋:

/zookeeper節點個數限額爲2,長度無限額。

 

setAcl命令

設置節點Acl。

此處重點說一下acl,acl由大部分組成:1爲scheme,2爲user,3爲permission,通常狀況下表示爲scheme:id:permissions。

其中scheme和id是相關的,下面將scheme和id一塊兒說明。

 

scheme和id

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)

permissions

CREATE(c): 建立權限,能夠在在當前node下建立child node

DELETE(d): 刪除權限,能夠刪除當前的node

READ(r): 讀權限,能夠獲取當前node的數據,能夠list當前node全部的child nodes

WRITE(w): 寫權限,能夠向當前node寫數據

ADMIN(a): 管理權限,能夠設置當前node的permission

綜上,一個簡單使用setAcl命令,則能夠爲:

setAcl /zookeeper/node1 world:anyone:cdrw

 getAcl命令

獲取節點Acl。

如getAcl /zookeeper/node1

'world,'anyone

: cdrwa

注:可參見setAcl命令。

sync命令

強制同步。

如sync /zookeeper

因爲請求在半數以上的zk server上生效就表示此請求生效,那麼就會有一些zk server上的數據是舊的。sync命令就是強制同步全部的更新操做。

redo命令

再次執行某命令。

如redo 10

其中10爲命令ID,需與history配合使用。

addauth命令

節點認證。

如addauth digest username:password,可參見setAcl命令digest處。

使用方法:

1、經過setAcl設置用戶名和密碼

setAcl pathdigest:username:base64(sha1(password)):crwda

2、認證

addauth digest username:password

delete命令

刪除節點。

如delete /zknode1

setquota命令

設置子節點個數和數據長度配額。

如setquota –n 4 /zookeeper/node 設置/zookeeper/node子節點個數最大爲4

setquota –b 100 /zookeeper/node 設置/zookeeper/node節點長度最大爲100

相關文章
相關標籤/搜索