zookeeper實戰教程

歡迎大家前來白嫖PDF。下圖回覆:666

本教程致力於最實用zookeeper教程,個別圖片粘貼有丟失,還有來領取原版。

pdf截圖

文章目錄

前言

聲明:參考來源互聯網,有任何爭議可以留言。站在前人的肩上,我們才能看的更遠。

本教程純手打,致力於最實用教程,不需要什麼獎勵,只希望多多轉發支持。
歡迎來我公衆號,希望可以結識你,你有什麼想看的可以催更,微信搜索:[JavaPub]

有任何問題都可以來談談,等你哦!

如果你對zookeeper有一定了解,那麼直接跳到你需要的知識點。

1. 什麼是Zookeeper

1.2.Zookeeper簡介

ZooKeeper: A Distributed Coordination Service for Distributed Applications
ZooKeeper is a distributed, open-source coordination service for distributed applications. It exposes a simple set of primitives that distributed applications can build upon to implement higher level services for synchronization, configuration maintenance, and groups and naming. It is designed to be easy to program to, and uses a data model styled after the familiar directory tree structure of file systems. It runs in Java and has bindings for both Java and C.
Coordination services are notoriously hard to get right. They are especially prone to errors such as race conditions and deadlock. The motivation behind ZooKeeper is to relieve distributed applications the responsibility of implementing coordination services from scratch.
https://zookeeper.apache.org/doc/current/zookeeperOver.html

官網地址:https://zookeeper.apache.org/doc/r3.4.12/index.html

上邊是Zookeeper官網的描述,as everyone knows,ZooKeeper是分佈式應用程序的分佈式協調服務。

1.3.爲什麼要用Zookeeper

學習一個東西,anyhow,知道爲什麼學它至關重要。

看到一個比較靠譜的例子:

一個團隊裏面,需要一個leader,leader是幹嘛用的?管理什麼的咱不說,就說如果外面的人,想問關於這個團隊的一切事情,首先就會去找這個leader,因爲他知道的最多,而且他的回答最靠譜。

比如產品經理小餅過來要人,作爲leader,老呂發現小耀最近沒有項目安排,於是把小耀安排給了小餅的項目;

過了一會,另一個產品小西也過來要人,老呂發現剛剛把小耀安排走了,已經沒人,於是就跟小西說,人都被你們產品要走了,你們產品自己去協調去。

如果老呂這時候忘了小耀已經被安排走了,把小耀也分配給小西,那到時兩個產品就要打架了。

這就是leader在團隊裏的【協調作用】。

同樣的,在分佈式系統中,也需要這樣的協調者,來回答系統下各個節點的提問。

Zookeeper能完美解決分佈式協調服務這個問題

但是這個例子屬於單機模式,當我們擴展爲三臺服務器集羣,小西過來問leader02要人,這時leader們信息還沒有同步。

這時就會涉及到Zookeeper的其他幾點特性:
1、配置信息同步
2、分佈式鎖控制
3、消息的發佈與訂閱(典型的生產者消費者模型)
4、集羣內節點狀態的快速感知

當信息還沒有同步完成時,不對外提供服務,阻塞住查詢請求,等待信息同步完成,再給查詢請求返回信息。

這樣的系統,就叫分佈式協調系統。誰能把這個數據同步的時間壓縮的更短,誰的請求響應就更快,誰就更出色,Zookeeper就是其中的佼佼者。

**它用起來像單機一樣,能夠提供數據強一致性,但是其實背後是多臺機器構成的集羣,不會有SPOF。**單點故障

2. Zookeeper介紹

2.1 百度百科

ZooKeeper是一個分佈式的,開放源碼的分佈式應用程序協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要組件。它是一個爲分佈式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分佈式同步、組服務等。
ZooKeeper的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。
ZooKeeper包含一個簡單的原語集,提供Java和C的接口。
ZooKeeper代碼版本中,提供了分佈式獨享鎖、選舉、隊列的接口,代碼在$zookeeper_home\src\recipes。其中分佈鎖和隊列有Java和C兩個版本,選舉只有Java版本。

看了上面的介紹,你還不知道zookeeper是什麼,那麼簡單來說:zookeeper=文件系統+監聽通知機制

包含如下四種節點:臨時節點(EPHEMERAL)、永久節點(persistent)、有編號節點(Persistent_sequential)、臨時有編號(Ephemral_ sequential)

2.2. 文件系統

Zookeeper維護一個類似文件系統的數據結構:

文件結構圖

2.3. 監聽通知機制

客戶端註冊監聽它關心的目錄節點,當目錄節點發生變化(數據改變、被刪除、子目錄節點增加刪除)時,zookeeper會通知客戶端。

  • 3、 Zookeeper能做什麼
    zookeeper功能非常強大,可以實現諸如分佈式應用配置管理、統一命名服務、狀態同步服務、集羣管理等功能,我們這裏拿比較簡單的分佈式應用配置管理爲例來說明。

假設我們的程序是分佈式部署在多臺機器上,如果我們要改變程序的配置文件,需要逐臺機器去修改,非常麻煩,現在把這些配置全部放到zookeeper上去,保存在 zookeeper 的某個目錄節點中,然後所有相關應用程序對這個目錄節點進行監聽,一旦配置信息發生變化,每個應用程序就會收到 zookeeper 的通知,然後從 zookeeper 獲取新的配置信息應用到系統中。

3. Zookeeper整體架構

架構圖

4. 快速入門(quick start)

4.1.安裝

  • 單機安裝

Zookeeper是解壓包,只需要安裝、解壓就可以啓動使用

wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
tar -zxf ./zookeeper-3.4.14.tar.gz

在conf目錄下,有默認啓動配置文件【zoo_sample.cfg】,複製一份到同級目錄下【zoo.cfg】。

配置文件解讀:

# tickTime這個時間是作爲zookeeper服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是說每個tickTime時間就會發送一個心跳。(以毫秒爲單位)
tickTime = 2000
# dataDir ZooKeeper的狀態存儲位置,看名字就知是數據目錄。在你的系統中檢查這個目錄是否存在,如果不存在手動創建,並且給予可寫權限。
dataDir = /path/to/zookeeper/data
# 這個端口就是客戶端連接Zookeeper服務器的端口,Zookeeper會監聽這個端口接受客戶端的訪問請求;
clientPort = 2181
# initLimit這個配置項是用來配置zookeeper接受客戶端(這裏所說的客戶端不是用戶連接zookeeper服務器的客戶端,而是zookeeper服務器集羣中連接到leader的follower 服務器)初始化連接時最長能忍受多少個心跳時間間隔數。
# 當已經超過10個心跳的時間(也就是tickTime)長度後 zookeeper 服務器還沒有收到客戶端的返回信息,那麼表明這個客戶端連接失敗。總的時間長度就是 5*2000=10秒。
initLimit = 5
# syncLimit這個配置項標識leader與follower之間發送消息,請求和應答時間長度,最長不能超過多少個tickTime的時間長度,總的時間長度就是2*2000=4秒
syncLimit = 2
# 日誌存放的位置
dataLogDir=/path/to/zookeeper/log

# 2888,3888 are election port
# 2888端口是zookeeper服務之間的通訊的端口,3888是zookeeper與其他應用程序通訊的端口。
# server.A=B:C:D中的A是一個數字,表示這個是第幾號服務器,B是這個服務器的IP地址,C第一個端口用來集羣成員的信息交換,表示這個服務器與集羣中的leader服務器交換信息的端口,D是在leader掛掉時專門用來進行選舉leader所用的端口。
server.1=localhost:2888:3888
  • 集羣安裝

    本例搭建的是僞集羣模式,即一臺機器上啓動三個zookeeper實例組成集羣,真正的集羣模式無非就是實例IP地址不同,搭建方法沒有區別

  • 配置說明

    1. tickTime:這個時間是作爲 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發送一個心跳。

    2. initLimit:這個配置項是用來配置 Zookeeper 接受客戶端(這裏所說的客戶端不是用戶連接 Zookeeper 服務器的客戶端,而是 Zookeeper 服務器集羣中連接到 Leader 的 Follower 服務器)初始化連接時最長能忍受多少個心跳時間間隔數。當已經超過 10個心跳的時間(也就是 tickTime)長度後 Zookeeper 服務器還沒有收到客戶端的返回信息,那麼表明這個客戶端連接失敗。總的時間長度就是 10*2000=20 秒

    3. syncLimit:這個配置項標識 Leader 與 Follower 之間發送消息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度,總的時間長度就是 5*2000=10秒

    4. dataDir:顧名思義就是 Zookeeper 保存數據的目錄,默認情況下,Zookeeper 將寫數據的日誌文件也保存在這個目錄裏。

    5. clientPort:這個端口就是客戶端連接 Zookeeper 服務器的端口,Zookeeper 會監聽這個端口,接受客戶端的訪問請求。

    6. server.A=B:C:D:其中 A 是一個數字,表示這個是第幾號服務器;B 是這個服務器的 ip 地址;C 表示的是這個服務器與集羣中的 Leader 服務器交換信息的端口;D 表示的是萬一集羣中的 Leader 服務器掛了,需要一個端口來重新進行選舉,選出一個新的 Leader,而這個端口就是用來執行選舉時服務器相互通信的端口。如果是僞集羣的配置方式,由於 B 都是一樣,所以不同的 Zookeeper 實例通信端口號不能一樣,所以要給它們分配不同的端口號。

  1. 僞分佈式,三個節點。

# cp conf/zoo_sample.cfg conf/zoo-1.cfg

# cp conf/zoo_sample.cfg conf/zoo-2.cfg

# cp conf/zoo_sample.cfg conf/zoo-3.cfg

  1. 修改dataDir和clientPort不同即可

    # vim conf/zoo-2.cfg

    dataDir=/tmp/zookeeper-2

    clientPort=2182

    # vim conf/zoo-2.cfg

    dataDir=/tmp/zookeeper-3

    clientPort=2183

    1. 標識Server ID,設置每個節點的server id

    # cd /tmp/zookeeper-1

    # vim myid

    # cd /tmp/zookeeper-2

    # vim myid

    # cd /tmp/zookeeper-3

    # vim myid

    1. 啓動

    # bin/zkServer.sh start conf/zoo-1.cfg
    # bin/zkServer.sh start conf/zoo-2.cfg
    # bin/zkServer.sh start conf/zoo-3.cfg

    1. 完成

    至此,集羣搭建完成,可以連接試試了

    bin/zkServer.sh status conf/zoo-1.cfg

4.2.啓動

[root@iz2zehz5b1m03ahtrhebcaz bin]# ./zkServer.sh 
ZooKeeper JMX enabled by default
Using config: /home/soft/zookeeper-3.4.8/bin/../conf/zoo.cfg
Usage: ./zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd}

進入到bin目錄下,

啓動

./zkServer.sh start

狀態

./zkServer.sh status

4.3.查詢

Zookeeper客戶端連接指令

進入zookeeper下bin目錄

[root@iz2zehz5b1m03ahtrhebcaz bin]# pwd
/home/soft/zookeeper-3.4.8/bin
[root@iz2zehz5b1m03ahtrhebcaz bin]# ll
total 44
-rwxr-xr-x 1 elasticsearch elasticsearch  232 Feb  6  2016 README.txt
-rwxr-xr-x 1 elasticsearch elasticsearch 1937 Feb  6  2016 zkCleanup.sh
-rwxr-xr-x 1 elasticsearch elasticsearch 1056 Feb  6  2016 zkCli.cmd
-rwxr-xr-x 1 elasticsearch elasticsearch 1534 Feb  6  2016 zkCli.sh
-rwxr-xr-x 1 elasticsearch elasticsearch 1628 Feb  6  2016 zkEnv.cmd
-rwxr-xr-x 1 elasticsearch elasticsearch 2696 Feb  6  2016 zkEnv.sh
-rwxr-xr-x 1 elasticsearch elasticsearch 1089 Feb  6  2016 zkServer.cmd
-rwxr-xr-x 1 elasticsearch elasticsearch 6773 Feb  6  2016 zkServer.sh
-rw-r--r-- 1 root          root          7850 May  4 13:26 zookeeper.out

可以看到很多腳本文件,通過zkCli.sh連接客戶端

./zkCli.sh -server 127.0.0.1:2181

通過ls /,查看已註冊服務,
例如查詢dubbo

ls /dubbo

可以看到dubbo服務地外提供的接口

消費者、生產者

ls /dubbo/com.ivan.service.provider.UserService/consumers

ls /dubbo/com.ivan.service.provider.UserService/providers

5. 常用指令

客戶端連接後整體使用和linux很相似,上一章做了一些介紹

  • zookeeper通過 ./bin/zkServer.sh start 命令啓動後,通過客戶端連接

./bin/zkCli.sh -server ip:port

[root@iz2zehz5b1m03ahtrhebcaz zookeeper-3.4.8]# ./bin/zkCli.sh -server 127.0.0.1:2181
Connecting to 127.0.0.1:2181
2020-05-14 13:52:21,530 [myid:] - INFO  [main:Environment@100] - Client environment:zookeeper.version=3.4.8--1, built on 02/06/2016 03:18 GMT
2020-05-14 13:52:21,533 [myid:] - INFO  [main:Environment@100] - Client environment:host.name=iz2zehz5b1m03ahtrhebcaz
2020-05-14 13:52:21,533 [myid:] - INFO  [main:Environment@100] - Client environment:java.version=1.8.0_144
2020-05-14 13:52:21,539 [myid:] - INFO  [main:Environment@100] - Client environment:java.vendor=Oracle Corporation
2020-05-14 13:52:21,540 [myid:] - INFO  [main:Environment@100] - Client environment:java.home=/home/soft/java/jdk1.8.0_144/jre
2020-05-14 13:52:21,540 [myid:] - INFO  [main:Environment@100] - Client environment:java.class.path=/home/soft/zookeeper-3.4.8/bin/../build/classes:/home/soft/zookeeper-3.4.8/bin/../build/lib/*.jar:/home/soft/zookeeper-3.4.8/bin/../lib/slf4j-log4j12-1.6.1.jar:/home/soft/zookeeper-3.4.8/bin/../lib/slf4j-api-1.6.1.jar:/home/soft/zookeeper-3.4.8/bin/../lib/netty-3.7.0.Final.jar:/home/soft/zookeeper-3.4.8/bin/../lib/log4j-1.2.16.jar:/home/soft/zookeeper-3.4.8/bin/../lib/jline-0.9.94.jar:/home/soft/zookeeper-3.4.8/bin/../zookeeper-3.4.8.jar:/home/soft/zookeeper-3.4.8/bin/../src/java/lib/*.jar:/home/soft/zookeeper-3.4.8/bin/../conf:.:/home/soft/java/jdk1.8.0_144/lib/dt.jar:/home/soft/java/jdk1.8.0_144/lib/tools.jar
2020-05-14 13:52:21,540 [myid:] - INFO  [main:Environment@100] - Client environment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
2020-05-14 13:52:21,540 [myid:] - INFO  [main:Environment@100] - Client environment:java.io.tmpdir=/tmp
2020-05-14 13:52:21,540 [myid:] - INFO  [main:Environment@100] - Client environment:java.compiler=<NA>
2020-05-14 13:52:21,540 [myid:] - INFO  [main:Environment@100] - Client environment:os.name=Linux
2020-05-14 13:52:21,540 [myid:] - INFO  [main:Environment@100] - Client environment:os.arch=amd64
2020-05-14 13:52:21,540 [myid:] - INFO  [main:Environment@100] - Client environment:os.version=3.10.0-514.26.2.el7.x86_64
2020-05-14 13:52:21,541 [myid:] - INFO  [main:Environment@100] - Client environment:user.name=root
2020-05-14 13:52:21,541 [myid:] - INFO  [main:Environment@100] - Client environment:user.home=/root
2020-05-14 13:52:21,541 [myid:] - INFO  [main:Environment@100] - Client environment:user.dir=/home/soft/zookeeper-3.4.8
2020-05-14 13:52:21,542 [myid:] - INFO  [main:ZooKeeper@438] - Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@799f7e29
Welcome to ZooKeeper!
JLine support is enabled
2020-05-14 13:52:21,579 [myid:] - INFO  [main-SendThread(127.0.0.1:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
2020-05-14 13:52:21,688 [myid:] - INFO  [main-SendThread(127.0.0.1:2181):ClientCnxn$SendThread@876] - Socket connection established to 127.0.0.1/127.0.0.1:2181, initiating session
2020-05-14 13:52:21,709 [myid:] - INFO  [main-SendThread(127.0.0.1:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server 127.0.0.1/127.0.0.1:2181, sessionid = 0x171de1d5d640005, negotiated timeout = 30000

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
  • 查看當前包含的內容
[zk: 127.0.0.1:2181(CONNECTED) 2] ls /
[cluster, controller_epoch, brokers, zookeeper, admin, isr_change_notification, consumers, log_dir_event_notification, latest_producer_id_block, config]
  • 創建一個 znode ,使用create /zkPro myData
[zk: 127.0.0.1:2181(CONNECTED) 3] create /zkPro MyData
Created /zkPro
  • 查一下創建的內容
[zk: 127.0.0.1:2181(CONNECTED) 4] ls /                
[cluster, controller_epoch, brokers, zookeeper, zkPro, admin, isr_change_notification, consumers, log_dir_event_notification, latest_producer_id_block, config]
  • 我們運行 get 命令來確認第二步中所創建的 znode 是否包含我們所創建的字符串:
[zk: 127.0.0.1:2181(CONNECTED) 5] get /zkPro MyData
MyData
cZxid = 0x338
ctime = Thu May 14 13:57:29 CST 2020
mZxid = 0x338
mtime = Thu May 14 13:57:29 CST 2020
pZxid = 0x338
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
  • 通過 set 命令來對 zk 所關聯的字符串進行設置:
WatchedEvent state:SyncConnected type:NodeDataChanged path:/zkPro
cZxid = 0x338
ctime = Thu May 14 13:57:29 CST 2020
mZxid = 0x339
mtime = Thu May 14 14:06:01 CST 2020
pZxid = 0x338
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0

  • 刪除節點
[zk: 127.0.0.1:2181(CONNECTED) 7] delete /zkPro
[zk: 127.0.0.1:2181(CONNECTED) 8] 

6. 應用場景

場景一 配置文件

我們在開發的時候,有時候需要獲取一些公共的配置,比如數據庫連接信息等,並且偶然可能需要更新配置。如果我們的服務器有N多臺的話,那修改起來會特別的麻煩,並且還需要重新啓動。這裏Zookeeper就可以很方便的實現類似的功能。

場景二 分佈式鎖

在我們日常的開發中,如果是單個進程中對共享資源的訪問,我們只需要用synchronized或者lock就能實現互斥操作。但是對於跨進程、跨主機、跨網絡的共享資源似乎就無能爲力了。

場景三 分佈式隊列

在日常使用中,特別是像生產者消費者模式中,經常會使用BlockingQueue來充當緩衝區的角色。但是在分佈式系統中這種方式就不能使用BlockingQueue來實現了,但是Zookeeper可以實現。

場景四 負載均衡

首先我們需要簡單的理解分佈式和集羣,通俗點說:分佈式就是將一個系統拆分到多個獨立運行的應用中(有可能在同一臺主機也有可能在不同的主機上),集羣就是將單個獨立的應用複製多分放在不同的主機上來減輕服務器的壓力。而Zookeeper不僅僅可以作爲分佈式集羣的服務註冊調度中心(例如dubbo),也可以實現集羣的負載均衡。

  • Zookeeper是一個功能非常強大的應用,除了上面幾種應用外,還有命名服務、分佈式協調通知等也是常用的場景。

7. 選舉機制

選舉機制,顧名思義就是投票選舉。

分佈式集羣開發的目的就是爲了保證系統的穩定運行,如果有一個服務掛掉,不會對整個系統造成大的影響。

Leader選舉是保證分佈式數據一致性的關鍵所在。當Zookeeper集羣中的一臺服務器出現以下兩種情況之一時,需要進入Leader選舉。

  1. 服務器初始化啓動。
  2. 服務器運行期間無法和Leader保持連接。
  • 情況一
1. 服務器啓動時期的Leader選舉

  若進行Leader選舉,則至少需要兩臺機器,這裏選取3臺機器組成的服務器集羣爲例。在集羣初始化階段,當有一臺服務器Server1啓動時,其單獨無法進行和完成Leader選舉,當第二臺服務器Server2啓動時,此時兩臺機器可以相互通信,每臺機器都試圖找到Leader,於是進入Leader選舉過程。選舉過程如下

  (1) 每個Server發出一個投票。由於是初始情況,Server1和Server2都會將自己作爲Leader服務器來進行投票,每次投票會包含所推舉的服務器的myid和ZXID,使用(myid, ZXID)來表示,此時Server1的投票爲(1, 0),Server2的投票爲(2, 0),然後各自將這個投票發給集羣中其他機器。

  (2) 接受來自各個服務器的投票。集羣的每個服務器收到投票後,首先判斷該投票的有效性,如檢查是否是本輪投票、是否來自LOOKING狀態的服務器。

  (3) 處理投票。針對每一個投票,服務器都需要將別人的投票和自己的投票進行PK,PK規則如下

    · 優先檢查ZXID。ZXID比較大的服務器優先作爲Leader。

    · 如果ZXID相同,那麼就比較myid。myid較大的服務器作爲Leader服務器。

  對於Server1而言,它的投票是(1, 0),接收Server2的投票爲(2, 0),首先會比較兩者的ZXID,均爲0,再比較myid,此時Server2的myid最大,於是更新自己的投票爲(2, 0),然後重新投票,對於Server2而言,其無須更新自己的投票,只是再次向集羣中所有機器發出上一次投票信息即可。

  (4) 統計投票。每次投票後,服務器都會統計投票信息,判斷是否已經有過半機器接受到相同的投票信息,對於Server1、Server2而言,都統計出集羣中已經有兩臺機器接受了(2, 0)的投票信息,此時便認爲已經選出了Leader。

  (5) 改變服務器狀態。一旦確定了Leader,每個服務器就會更新自己的狀態,如果是Follower,那麼就變更爲FOLLOWING,如果是Leader,就變更爲LEADING。
  • 情況二
 2. 服務器運行時期的Leader選舉

  在Zookeeper運行期間,Leader與非Leader服務器各司其職,即便當有非Leader服務器宕機或新加入,此時也不會影響Leader,但是一旦Leader服務器掛了,那麼整個集羣將暫停對外服務,進入新一輪Leader選舉,其過程和啓動時期的Leader選舉過程基本一致。假設正在運行的有Server1、Server2、Server3三臺服務器,當前Leader是Server2,若某一時刻Leader掛了,此時便開始Leader選舉。選舉過程如下

  (1) 變更狀態。Leader掛後,餘下的非Observer服務器都會講自己的服務器狀態變更爲LOOKING,然後開始進入Leader選舉過程。

  (2) 每個Server會發出一個投票。在運行期間,每個服務器上的ZXID可能不同,此時假定Server1的ZXID爲123,Server3的ZXID爲122;在第一輪投票中,Server1和Server3都會投自己,產生投票(1, 123),(3, 122),然後各自將投票發送給集羣中所有機器。

  (3) 接收來自各個服務器的投票。與啓動時過程相同。

  (4) 處理投票。與啓動時過程相同,此時,Server1將會成爲Leader。

  (5) 統計投票。與啓動時過程相同。

  (6) 改變服務器的狀態。與啓動時過程相同。

總結:

  1. 在選舉時每個節點都有一個(myid,ZXID)表示;
  2. 對於初始化或leader宕機時,每個server發出一個投票給集羣其他機器,所有請求掛起,開始選舉(如實例一);
  3. 超過半數的投票,就會成爲Leader;
  4. 比較自己的選票和接收到的投票,優先比較ZXID,再比較myid。如果大於自己,更換自己的選票並告訴其他server;
  • ZXID 是指當前服務器數據越新,其成爲Leader可能性越大。
  • myid 是指當前server編號

8. 三大功能

  1. 爲用戶提供數據的註冊和查詢服務
  2. 爲用戶提供數據節點的監聽註冊服務
  3. 跟用戶之間保持心跳通信以感知用戶的狀態

9. Java Api 操作zookeeper

  • 分佈式配置中心
  1. jar引入
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.6.1</version>
        </dependency>
  1. 創建節點
[zk: localhost:2181(CONNECTED) 6] create /username javapub
Created /username
  1. 啓動客戶端代碼
package javapub;

/**
 * @author wangshiyu rodert
 * @date 2020/5/18 13:15
 * @description
 */
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

/**
 * 分佈式配置中心demo
 * @author
 *
 */
public class ZooKeeperProSync implements Watcher {

    private static CountDownLatch connectedSemaphore = new CountDownLatch(1);
    private static ZooKeeper zk = null;
    private static Stat stat = new Stat();

    public static void main(String[] args) throws Exception {
        //zookeeper配置數據存放路徑
        String path = "/username";
        //連接zookeeper並且註冊一個默認的監聽器
        zk = new ZooKeeper("127.0.0.1:2181", 5000, //
                new ZooKeeperProSync());
        //等待zk連接成功的通知
        connectedSemaphore.await();
        //獲取path目錄節點的配置數據,並註冊默認的監聽器
        System.out.println(new String(zk.getData(path, true, stat)));

        Thread.sleep(Integer.MAX_VALUE);
    }

    public void process(WatchedEvent event) {
        if (KeeperState.SyncConnected == event.getState()) {  //zk連接成功通知事件
            if (EventType.None == event.getType() && null == event.getPath()) {
                connectedSemaphore.countDown();
            } else if (event.getType() == EventType.NodeDataChanged) {  //zk目錄節點數據變化通知事件
                try {
                    System.out.println("配置已修改,新值爲:" + new String(zk.getData(event.getPath(), true, stat)));
                } catch (Exception e) {
                }
            }
        }
    }
}

啓動java客戶端代碼,正確讀取到 /username 目錄下數據,javapub

  1. 修改 /username 下數據
[zk: localhost:2181(CONNECTED) 7] set /username javapub-rodert
cZxid = 0x4
ctime = Mon May 18 13:20:59 CST 2020
mZxid = 0x6
mtime = Mon May 18 13:27:54 CST 2020
pZxid = 0x4
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 14
numChildren = 0

客戶端同步如下:
配置已修改,新值爲:javapub-rodert

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章