一塊兒走進動物園管理員——ZooKeeper

1、ZooKeeper簡介

1. ZooKeeper是什麼

​ Apache ZooKeeper是一個開源的分佈式服務框架,爲分佈式應用提供協調服務,用來解決分佈式應用中的數據管理問題,如:配置管理、域名服務、分佈式同步、集羣管理等
官網 https://zookeeper.apache.org/
ZooKeeper視頻教程 http://edu.51cto.com/course/16190.htmlhtml

一塊兒走進動物園管理員——ZooKeeper

2. ZooKeeper組成

​ 主要包括兩部分:文件系統、通知機制java

2.1 文件系統

​ ZooKeeper維護一個相似Linux文件系統的數據結構,用於存儲數據node

  • 數據模型結構是一種樹形結構,由許多節點構成
  • 每一個節點叫作ZNode(ZooKeeper Node)
  • 每一個節點對應一個惟一路徑,經過該路徑來標識節點,如 /app1/p_2
  • 每一個節點只能存儲大約1M的數據

一塊兒走進動物園管理員——ZooKeeper

​ 節點類型有四種:算法

  • 持久化目錄節點 persistent數據庫

    客戶端與服務器斷開鏈接,該節點仍然存在apache

  • 持久化順序編號目錄節點 persistent_sequential數組

    客戶端與服務器斷開鏈接,該節點仍然存在,此時節點會被順序編號,如:00000一、000002.....bash

  • 臨時目錄節點 ephemeral服務器

    客戶端與服務器斷開鏈接,該節點會被刪除session

  • 臨時順序編號目錄節點 ephemeral_sequential

    客戶端與服務器斷開鏈接,該節點會被刪除,此時節點會被順序編號,如:00000一、000002.....

2.2 通知機制

​ ZooKeeper是一個基於觀察者模式設計的分佈式服務管理框架

  1. ZooKeeper負責管理和維護項目的公共數據,並授受觀察者的註冊(訂閱)
  2. 一旦這些數據發生變化,ZooKeeper就會通知已註冊的觀察者
  3. 此時觀察者就能夠作出相應的反應

​ 簡單來講,客戶端註冊監聽它關心的目錄節點,當目錄節點發生變化時,ZooKeeper會通知客戶端

​ ZooKeeper是一個訂閱中心(註冊中心)

3. 應用場景

3.1 配置管理

​ 場景:集羣環境、服務器的許多配置都是相同的,如:數據庫鏈接信息,當須要修改這些配置時必須同時修改每臺服務器,很麻煩

​ 解決:把這些配置所有放到ZooKeeper上,保存在ZooKeeper的某個目錄節點中,而後全部的應用程序(客戶端)對這個目錄節點進行監視Watch,一旦配置信息發生變化,ZooKeeper會通知每一個客戶端,而後從ZooKeeper獲取新的配置信息,並應用到系統中。

一塊兒走進動物園管理員——ZooKeeper

3.2 集羣管理

​ 場景:集羣環境下,如何知道有多少臺機器在工做?是否有機器退出或加入?須要選舉一個總管master,讓總管來管理集羣

​ 解決:在父目錄GroupMembers下爲全部機器建立臨時目錄節點,而後監聽父目錄節點的子節點變化,一旦有機器掛掉,該機器與ZooKeeper的鏈接斷開,其所建立的臨時目錄節點被刪除,全部其餘機器都會收到通知。當有新機器加入時也是一樣的道理。

​ 選舉master:爲全部機器建立臨時順序編號目錄節點,給每臺機器編號,而後每次選取編號最小的機器做爲master

一塊兒走進動物園管理員——ZooKeeper

3.3 負載均衡

​ ZooKeeper自己是不提供負載均衡策略的,須要本身實現,因此準確的說,是在負載均衡中使用ZooKeeper來作集羣的協調(也稱爲軟負載均衡)

​ 實現思路:

  1. 將ZooKeeper做爲服務的註冊中心,全部服務器在啓動時向註冊中心登錄本身可以提供的服務
  2. 服務的調用者到註冊中心獲取可以提供所須要服務的服務器列表,而後本身根據負載均衡算法,從中選取一臺服務器進行鏈接
  3. 當服務器列表發生變化時,如:某臺服務器宕機下線,或新機器加入,ZooKeeper會自動通知調用者從新獲取服務列表

​ 實際上利用了ZooKeeper的特性,將ZooKeeper用爲服務的註冊和變動通知中心

一塊兒走進動物園管理員——ZooKeeper

2、ZooKeeper安裝

1. 安裝

​ ZooKeeper通常都運行在Linux平臺

​ 步驟:

  1. 解壓zookeeper-3.4.13.tar.gz

    cd ~/software
    tar -zxf zookeeper-3.4.13.tar.gz
  2. 配置

    # 建立存放數據文件的目錄
    cd zookeeper-3.4.13/
    mkdir data
    # 建立配置文件
    cd conf
    cp zoo_sample.cfg zoo.cfg  # 默認使用的是zoo.cfg,名稱固定
    # 修改配置文件
    vi zoo.cfg
    dataDir=../data  # 指定數據存放目錄

    一塊兒走進動物園管理員——ZooKeeper

  3. 啓動zookeeper

    cd bin
    ./zkServer.sh start | stop | status | restart  # 啓動|中止|查看狀態|重啓

    一塊兒走進動物園管理員——ZooKeeper

  4. 客戶端鏈接zookeeper

    ./zkCli.sh  # 啓動客戶端,默認鏈接本機的2181端口
    或
    ./zkCli.sh -server 服務器地址:端口 # 鏈接指定主機、指定端口的zookeeper
    quit  # 退出客戶端

2. 配置文件

配置項 含義 說明
tickTime=2000 心跳時間 維持心跳的時間間隔,單位是毫秒<br>在zookeeper中全部的時間都是以這個時間爲基礎單元,進行整數倍配置
initLimit=10 初始通訊時限 用於zookeeper集羣,此時有多臺zookeeper服務器,其中一個爲Leader,其餘都爲Follower
syncLimit=5 同步通訊時限 在運行時Leader經過心跳檢測與Follower進行通訊,若是超過syncLimit*tickTime時間還未收到響應,則認爲該Follower已經宕機
dataDir=../data 存儲數據的目錄 數據文件也稱爲snapshot快照文件
clientPort=2181 端口號 默認爲2181
maxClientCnxns=60 單個客戶端的最大鏈接數限制 默認爲60,能夠設置爲0,表示沒有限制
autopurge.snapRetainCount=3 保留文件的數量 默認3個
autopurge.purgeInterval=1 自動清理快照文件和事務日誌的頻率 默認爲0,表示不開啓自動清理,單位是小時
dataLogDir= 存儲日誌的目錄 未指定時日誌文件也存放在dataDir中,爲了性能最大化,通常建議把dataDir和dataLogDir分別放到不一樣的磁盤上

一塊兒走進動物園管理員——ZooKeeper

3、客戶端操做

1. 經常使用命令

命令 做用 說明
help 查看幫助 查看全部操做命令
ls 節點路徑 查看指定節點下的內容
ls2 節點路徑 查看指定節點的詳細信息 查看全部子節點和當前節點的狀態
create 節點路徑 內容 建立普通節點 若是內容中有空格,則須要使用對雙引號引發來
get 節點路徑 獲取節點中的值
create -e 節點路徑 內容 建立臨時節點 當鏈接斷開後,節點會被自動刪除
create -s 節點路徑 內容 建立順序編號節點 即帶序號的節點
delete 節點路徑 刪除節點 只能刪除空節點,即不能有子節點
rmr 節點路徑 遞歸刪除節點 remove recursion
stat 節點路徑 查看節點狀態
set 節點路徑 新值 修改節點內容

2. 詳解

​ 查看指定節點的詳細信息: ls2 /
一塊兒走進動物園管理員——ZooKeeper

# 子節點名稱數組
[zookeeper]

# -----------節點的狀態信息,也稱爲stat結構體-------------------
# 建立該znode的事務的zxid(ZooKeeper Transaction ID)
# 事務ID是ZooKeeper爲每次更新操做/事務操做分配一個全局惟一的id,表示zxid,值越小,表示越先執行
cZxid = 0x0  # 0x0表示十六進制數0
# 建立時間
ctime = Thu Jan 01 08:00:00 CST 1970
# 最後一次更新的zxid
mZxid = 0x0
# 最後一次更新的時間
mtime = Thu Jan 01 08:00:00 CST 1970
# 最後更新的子節點的zxid
pZxid = 0x0
# 子節點的變化號,表示子節點被修改的次數,-1表示從未被修改過
cversion = -1
# 當前節點的變化號,0表示從未被修改過
dataVersion = 0
# 訪問控制列表的變化號 access control list
aclVersion = 0
# 若是臨時節點,表示當前節點的擁有者的sessionId
# 若是不是臨時節點,則值爲0
ephemeralOwner = 0x0
# 數據長度
dataLength = 0
# 子節點數據
numChildren = 1

​ 順序編號節點:

  • 順序編號會緊跟在節點名稱後面,節點最終名稱爲:節點名+序號,如/test0000000005
  • 順序編號是一個遞增的計數器
  • 順序編號是由父節點維護,從已有的子節點個數開始(包括臨時節點和被刪除的節點)
  • 若是子節點爲空,則從0000000000開始,依次遞增1
  • 在分佈式系統中,順序編號能夠被用於爲全部的事件進行全局排序,這樣客戶端就能夠根據序號推斷事件的順序

4、ZooKeeper集羣

1. 配置集羣

​ 步驟:

  1. 準備多臺ZooKeeper服務器

  2. 配置ZooKeeper服務器

    在每臺服務器的conf/zoo.cfg文件中添加以下內容:

    server.20=192.168.4.20:2888:3888
    server.21=192.168.4.21:2888:3888
    server.22=192.168.4.22:2888:3888

    格式:server.A=B:C:D

    • A表示這臺服務器的編號ID,是一個數字
    • B表示服務器的IP地址或域名
    • C表示這臺服務器與集羣中的Leader交換信息時使用的端口
    • D表示執行選舉Leader服務器時互相通訊的端口
  3. 建立myid配置文件

    在集羣環境下,須要在dataDir目錄中建立一個名爲myid的文件,文件內容是當前服務器的編號ID,即上面配置的A

    cd data
    echo A的值 > myid

    ZooKeeper啓動時會讀取這個文件,將裏面的數字與zoo.cfg中配置的server.A進行比較,從而判斷這臺服務器是哪一個

  4. 測試集羣環境

    啓動全部ZooKeeper服務器,查看狀態

    此時在某臺服務器上執行更新操做時,其餘服務器也會同步

2. 集羣特性

  • 一個ZooKeeper集羣中,有一個領導者Leader和多個跟隨者Follower
  • Leader負責進行投票的發起和決議,更新系統狀態
  • Follower用於接收客戶端的請求並向客戶端返回結果,在選舉Leader過程當中參與投票
  • 半數機制:集羣中只要有半數以上節點存活,集羣就可以正常工做,因此通常集羣中的服務器個數都爲奇數
  • 全局數據一致:集羣中每臺服務器保存一份相同的數據副本,不論客戶端鏈接到哪一個服務器,數據都是一致的
  • 更新請求順序執行:來自同一個客戶端的更新請求,按其發送順序依次執行
  • 數據更新的原子性:一次數據更新,要麼成功,要麼失敗
  • 實時性:在必定的時間範圍內,客戶端能讀取到最新數據

3. 選舉機制

​ ZooKeeper在提供服務時會自動選舉一個節點服務器做爲Leader,其餘都是Follower

一塊兒走進動物園管理員——ZooKeeper

​ 選舉流程:

  1. Server1啓動,給本身投票,而後發送投票信息,因爲其它服務器都還沒啓動,因此它發現的消息收不到任何反饋,此時Server1爲Looking狀態
  2. Server2啓動,給本身投票,同時與Server1通訊交換選舉結果,因爲Server2的id值較大,因此Server2勝出,但因爲投票數沒有過半,此時Server1和Server2都爲Looking狀態
  3. Server3啓動,給本身投票,同時與Server1和Server2通訊交換選舉結果,因爲Server3的id值較大,因此Server3勝出,此時票數已通過半,因此Server3爲Leader,Server1和Server2爲Follower
  4. Server4啓動,給本身投票,同時與Server一、Server二、Server3通訊交換選舉結果,儘管Server4的id較大,但因爲集羣中已經存在Leader,因此Server4只能爲Follower
  5. Server5啓動,同Server4相似,只能爲Follower

​ 總結:

  • 每一個服務器在啓動時都會選擇本身,而後將投票信息發送出去
  • 服務器編號ID越大,在選擇算法中的權重越大
  • 投票數必須過半,才能選出Leader
  • 誰是Leader:啓動順序的前集羣數/2+1個服務器中,id值最大的會成爲Leader

4. 監聽機制

4.1 監聽節點值的變化

# 在集羣的A服務器,監聽某個節點值的變化
get /yyy watch

# 在集羣的B服務器,修改對應節點的值
set /yyy myyyy

# 此時A服務器會收到事件NodeDataChanged
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/yyy

監聽Watch事件是一個一次性的觸發器,當數據改變時只會觸發一次,若是之後這個數據再發生改變,則不會再次觸發

4.2 監聽節點的子節點變化

# 在集羣的A服務器,監聽某個節點的子節點的變化 
ls /yyy watch

# 在集羣的B服務器,建立/修改/刪除對應節點的子節點
create /yyy/hello hello

# 此時A服務器會收到事件NodeChildrenChanged
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/yyy

5、Java訪問ZooKeeper

Java操做Zookeeper很簡單,只須要添加ZooKeeper客戶端的依賴便可,能夠進行節點信息的獲取、管理等。

​ 步驟:

  1. 添加jar包

    <!--ZooKeeper客戶端-->
    <dependency>
       <groupId>org.apache.zookeeper</groupId>
       <artifactId>zookeeper</artifactId>
       <version>3.4.13</version>
    </dependency>
  2. 操做

    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
       //獲取ZooKeeper的鏈接,即建立ZooKeeper的客戶端
       String connectString = "127.0.0.1:2181";  //服務器地址
       int sessionTimeout = 3000; //超時時間,單位爲毫秒
       Watcher watcher = new MyWatcher();
       ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, watcher);
    
       Thread.sleep(2000);
       System.out.println(zkClient.getState());
    
       /**
            * 操做ZooKeeper
            */
       //查看指定節點下的內容
       List<String> children = zkClient.getChildren("/", true);//第二個參數表示是否監視該節點
       System.out.println(children);
    
       //建立節點,OPEN_ACL_UNSAFE表示acl權限列表爲徹底開放,PERSISTENT表示節點類型爲持久化節點
       zkClient.create("/world", "世界".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    
       //獲取節點的數據(節點的值和節點狀態Stat)
       byte[] data = zkClient.getData("/world", true, null);
       System.out.println(new String(data));
    
       Stat stat = new Stat();
       byte[] data = zkClient.getData("/hello", true, stat);
       byte[] data = zkClient.getData("/hello", new DataWatcher(), stat);
       System.out.println(new String(data));
       System.out.println(stat);
       System.out.println(stat.getCtime());
       System.out.println(stat.getVersion());
       System.out.println(stat.getDataLength());
    
       //修改節點的數據
       // zkClient.setData("/hello","aaa".getBytes(),stat.getVersion()); //第三個參數表示當前節點的數據版本,通常先獲取數據stat,而後指定數據版本
       zkClient.setData("/hello", "bbb".getBytes(), -1);  //也能夠設置爲-1,表示不檢測版本
    
       //刪除節點
       zkClient.delete("/hello", -1);
    
       //判斷節點是否存在
       System.out.println(zkClient.exists("/hello",false));  //存在時返回節點狀態,不存在則返回null
    
       //休眠
       Thread.sleep(1000000);
    
       //關閉鏈接
       zkClient.close();
    }

ZooKeeper快速入門視頻,連接:http://edu.51cto.com/course/16190.html

相關文章
相關標籤/搜索