之前整理過一篇文章《zookeeper 分布式鎖服務》,本文介紹的 Zookeeper 是以 3.4.5 這個穩定版本為基礎,最新的版本可以通過官網 http://hadoop.apache.org/zookeeper/來擷取,Zookeeper 的安裝非常簡單,下面将從單機模式和叢集模式兩個方面介紹 Zookeeper 的Windows安裝和配置.
首先需要安裝JdK,從Oracle的Java網站下載下傳,安裝很簡單,就不再詳述。
單機模式
單機安裝非常簡單,隻要擷取到 Zookeeper 的壓縮包并解壓到某個目錄如:C:\zookeeper-3.4.5\下,Zookeeper 的啟動腳本在 bin 目錄下,Windows 下的啟動腳本是 zkServer.cmd。
在你執行啟動腳本之前,還有幾個基本的配置項需要配置一下,Zookeeper 的配置檔案在 conf 目錄下,這個目錄下有 zoo_sample.cfg 和 log4j.properties,你需要做的就是将 zoo_sample.cfg 改名為 zoo.cfg,因為 Zookeeper 在啟動時會找這個檔案作為預設配置檔案。下面詳細介紹一下,這個配置檔案中各個配置項的意義。
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=C:\\zookeeper-3.4.5\\data
dataLogDir=C:\\zookeeper-3.4.5\\log
# the port at which the clients will connect
clientPort=2181
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
- tickTime:這個時間是作為 Zookeeper 伺服器之間或用戶端與伺服器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發送一個心跳。
- dataDir:顧名思義就是 Zookeeper 儲存資料的目錄,預設情況下,Zookeeper 将寫資料的日志檔案也儲存在這個目錄裡。
- dataLogDir:顧名思義就是 Zookeeper 儲存日志檔案的目錄
- clientPort:這個端口就是用戶端連接配接 Zookeeper 伺服器的端口,Zookeeper 會監聽這個端口,接受用戶端的通路請求。
當這些配置項配置好後,你現在就可以啟動 Zookeeper 了,啟動後要檢查 Zookeeper 是否已經在服務,可以通過 netstat – ano 指令檢視是否有你配置的 clientPort 端口号在監聽服務。
叢集模式
Zookeeper 不僅可以單機提供服務,同時也支援多機組成叢集來提供服務。實際上 Zookeeper 還支援另外一種僞叢集的方式,也就是可以在一台實體機上運作多個 Zookeeper 執行個體,下面将介紹叢集模式的安裝和配置。
Zookeeper 的叢集模式的安裝和配置也不是很複雜,所要做的就是增加幾個配置項。叢集模式除了上面的三個配置項還要增加下面幾個配置項:
initLimit=5
syncLimit=2
server.1=192.168.211.1:2888:3888
server.2=192.168.211.2:2888:3888
- initLimit:這個配置項是用來配置 Zookeeper 接受用戶端(這裡所說的用戶端不是使用者連接配接 Zookeeper 伺服器的用戶端,而是 Zookeeper 伺服器叢集中連接配接到 Leader 的 Follower 伺服器)初始化連接配接時最長能忍受多少個心跳時間間隔數。當已經超過 10 個心跳的時間(也就是 tickTime)長度後 Zookeeper 伺服器還沒有收到用戶端的傳回資訊,那麼表明這個用戶端連接配接失敗。總的時間長度就是 5*2000=10 秒
- syncLimit:這個配置項辨別 Leader 與 Follower 之間發送消息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度,總的時間長度就是 2*2000=4 秒
- server.A=B:C:D:其中 A 是一個數字,表示這個是第幾号伺服器;B 是這個伺服器的 ip 位址;C 表示的是這個伺服器與叢集中的 Leader 伺服器交換資訊的端口;D 表示的是萬一叢集中的 Leader 伺服器挂了,需要一個端口來重新進行選舉,選出一個新的 Leader,而這個端口就是用來執行選舉時伺服器互相通信的端口。如果是僞叢集的配置方式,由于 B 都是一樣,是以不同的 Zookeeper 執行個體通信端口号不能一樣,是以要給它們配置設定不同的端口号。
- 除了修改 zoo.cfg 配置檔案,叢集模式下還要配置一個檔案 myid,這個檔案在 dataDir 目錄下,這個檔案裡面就有一個資料就是 A 的值,Zookeeper 啟動時會讀取這個檔案,拿到裡面的資料與 zoo.cfg 裡面的配置資訊比較進而判斷到底是那個 server。
資料模型
Zookeeper 會維護一個具有層次關系的資料結構,它非常類似于一個标準的檔案系統,如圖 1 所示:
Zookeeper 這種資料結構有如下這些特點:
- 每個子目錄項如 NameService 都被稱作為 znode,這個 znode 是被它所在的路徑唯一辨別,如 Server1 這個 znode 的辨別為 /NameService/Server1
- znode 可以有子節點目錄,并且每個 znode 可以存儲資料,注意 EPHEMERAL 類型的目錄節點不能有子節點目錄
- znode 是有版本的,每個 znode 中存儲的資料可以有多個版本,也就是一個通路路徑中可以存儲多份資料
- znode 可以是臨時節點,一旦建立這個 znode 的用戶端與伺服器失去聯系,這個 znode 也将自動删除,Zookeeper 的用戶端和伺服器通信采用長連接配接方式,每個用戶端和伺服器通過心跳來保持連接配接,這個連接配接狀态稱為 session,如果 znode 是臨時節點,這個 session 失效,znode 也就删除了
- znode 的目錄名可以自動編号,如 App1 已經存在,再建立的話,将會自動命名為 App2
- znode 可以被監控,包括這個目錄節點中存儲的資料的修改,子節點目錄的變化等,一旦變化可以通知設定監控的用戶端,這個是 Zookeeper 的核心特性,Zookeeper 的很多功能都是基于這個特性實作的,後面在典型的應用場景中會有執行個體介紹
如何使用
Zookeeper 作為一個分布式的服務架構,主要用來解決分布式叢集中應用系統的一緻性問題,它能提供基于類似于檔案系統的目錄節點樹方式的資料存儲,但是 Zookeeper 并不是用來專門存儲資料的,它的作用主要是用來維護和監控你存儲的資料的狀态變化。通過監控這些資料狀态的變化,進而可以達到基于資料的叢集管理.
通過C#代碼使用zookeeper
Zookeeper的使用主要是通過建立其Nuget ZooKeeperNet包下的Zookeeper執行個體,并且調用其接口方法進行的,主要的操作就是對znode的增删改操作,監聽znode的變化以及處理。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ZooKeeperNet;
namespace ZookeeperDemo
{
class Watcher : IWatcher
{
public void Process(WatchedEvent @event)
{
if (@event.Type == EventType.NodeDataChanged)
{
Console.WriteLine(@event.Path);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ZooKeeperNet;
namespace ZookeeperDemo
{
class Program
{
static void Main(string[] args)
{
//建立一個Zookeeper執行個體,第一個參數為目标伺服器位址和端口,第二個參數為Session逾時時間,第三個為節點變化時的回調方法
using (ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", new TimeSpan(0, 0, 0, 50000), new Watcher()))
{
var stat = zk.Exists("/root",true);
////建立一個節點root,資料是mydata,不進行ACL權限控制,節點為永久性的(即用戶端shutdown了也不會消失)
//zk.Create("/root", "mydata".GetBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.Persistent);
//在root下面建立一個childone znode,資料為childone,不進行ACL權限控制,節點為永久性的
zk.Create("/root/childone", "childone".GetBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.Persistent);
//取得/root節點下的子節點名稱,傳回List<String>
zk.GetChildren("/root", true);
//取得/root/childone節點下的資料,傳回byte[]
zk.GetData("/root/childone", true, null);
//修改節點/root/childone下的資料,第三個參數為版本,如果是-1,那會無視被修改的資料版本,直接改掉
zk.SetData("/root/childone", "childonemodify".GetBytes(), -1);
//删除/root/childone這個節點,第二個參數為版本,-1的話直接删除,無視版本
zk.Delete("/root/childone", -1);
}
}
}
}
淺析
建立連接配接:
1.擷取服務主機清單
2.設定逾時時間
3.注冊用戶端事件
4.以線程安全的方式建立請求連接配接(啟動用戶端請求隊列,循環隊列基于socket通信、根據請求類型執行不同的請求動作)
請求流程:
構造請求頭、構造request,reponse、構造響應頭、構造Packet對象,packet對象準備好後,把整個對象放入一個outgoingQueue
packet被放入outgoingQueue中,等待SendThread把packet對應的内容發送給server。server處理分3步在doio方法中ReadLength ReadConnectResult ReadResponse,直到ReadResponse方法中确定packet請求結束。
響應流程:
針對心跳的ping請求的resp,針對auth請求的resp,一般接口請求的resp,如果接口請求要求了watcher,當watcher關注的内容有變化時的notification
鎖相關部分API方法:
建立節點:create
demo:zk.Create(Dir, severname.GetBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.Persistent);
其中CreateMode分為4類Persistent、PersistentSequential、Ephemeral、EphemeralSequential
PERSISTENT 建立持久化節點,對應機器關閉連接配接後節點/資料不會消失
PERSISTENT_SEQUENTIAL 如果PATH是以’/’結尾則以這個PATH作為父節點,建立一個子節點,其子節點名字是一個按先後順序排列的數值;否則建立一個名字是‘/’後面字元加上先後順序排列的數值字元串的節點,同樣建立持久節點
EPHEMERAL 建立瞬時節點,Zookeeper在感覺連接配接機器當機後會清除它建立的瞬時節點
EPHEMERAL_SEQUENTIAL 穿件瞬時順序節點,和PERSISTENT_SEQUENTIAL一樣,差別在于它是瞬時的
删除節點 delete
demo :zk.Delete(Dir, -1);
前一個參數代表節點名稱(一般用作路徑),後一個是版本号 -1表示全比對
檢視節點 exists
demo : zk.Exists(Dir, new MyWatch2());
擷取資料 getData
demo :zk.GetData(Dir, new MyWatch2(), stat);
擷取一個節點的資料,可注入watcher
設定資料 setData
demo : zk.SetData(Dir, new byte[1], 1);
擷取下級節點集合 GetChildren
demo :zk.GetChildren(Dir, true);
存儲
znodes類似檔案和目錄。但它不是一個典型的檔案系統,zookeeper資料儲存在記憶體中,這意味着zookeeper可以實作高吞吐量和低延遲。
watcher
Zookeeper有兩種watches,一種是data watches,另一種是child watches。其中,getData()和exists()以及create()等會添加data watches,getChildren()會添加child watches。而delete()涉及到删除資料和子節點,會同時觸發data watches和child watches。
示例代碼下載下傳:ZookeeperDemo.zip
相關文章:
ZooKeeper配置 (二)
zookeeper 安裝配置(三)
Zookeeper .Net Client
https://github.com/devhong/Zookeeper.Net
基于ZooKeeper建構大規模配置系統II http://xahxy.blog.hexun.com/83250722_d.html
分布式服務架構 Zookeeper -- 管理分布式環境中的資料 http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/
基于ZooKeeper的分布式Session實作 http://blog.csdn.net/jacktan/article/details/6112806
ZooKeeper介紹、分析、了解 http://mazd1002.blog.163.com/blog/static/6657496520111120101753463/
ZooKeeper實作分布式隊列Queue http://blog.fens.me/zookeeper-queue/
李欣:ZooKeeper在攜程的使用及前景 http://v.csdn.hudong.com/open/view/detail/83-SDCC2012-ctrip-ZooKeeper
Storm-源碼分析- Storm中Zookeeper的使用
Zookeeper 的學習與運用
原文位址:https://www.cnblogs.com/shanyou/p/3221990.html