1. 程式人生 > >一篇文章帶你入門Zookeeper

一篇文章帶你入門Zookeeper

Zookeeper是什麼


官方文件上這麼解釋zookeeper,它是一個分散式服務框架,是Apache Hadoop 的一個子專案,它主要是用來解決分散式應用中經常遇到的一些資料管理問題,如:統一命名服務、狀態同步服務、叢集管理、分散式應用配置項的管理等。

 

上面的解釋有點抽象,簡單來說zookeeper=檔案系統+監聽通知機制。

 

1、 檔案系統

Zookeeper維護一個類似檔案系統的資料結構:

每個子目錄項如 NameService 都被稱作為 znode(目錄節點),和檔案系統一樣,我們能夠自由的增加、刪除znode,在一個znode下增加、刪除子znode,唯一的不同在於znode是可以儲存資料的。

有四種類型的znode:

PERSISTENT-持久化目錄節點

客戶端與zookeeper斷開連線後,該節點依舊存在

PERSISTENT_SEQUENTIAL-持久化順序編號目錄節點

客戶端與zookeeper斷開連線後,該節點依舊存在,只是Zookeeper給該節點名稱進行順序編號

EPHEMERAL-臨時目錄節點

客戶端與zookeeper斷開連線後,該節點被刪除

EPHEMERAL_SEQUENTIAL-臨時順序編號目錄節點

客戶端與zookeeper斷開連線後,該節點被刪除,只是Zookeeper給該節點名稱進行順序編號

 

2、 監聽通知機制

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

就這麼簡單,下面我們看看Zookeeper能做點什麼呢?

 

Zookeeper能做什麼


zookeeper功能非常強大,可以實現諸如分散式應用配置管理、統一命名服務、狀態同步服務、叢集管理等功能,我們這裡拿比較簡單的分散式應用配置管理為例來說明。

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

如上,你大致應該瞭解zookeeper是個什麼東西,大概能做些什麼了,我們馬上來學習下zookeeper的安裝及使用,並開發一個小程式來實現zookeeper這個分散式配置管理的功能。

 

Zookeeper單機模式安裝


Step1:配置JAVA環境,檢驗環境:java -version

Step2:下載並解壓zookeeper

# cd /usr/local
# wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper-3.4.12.tar.gz
# tar -zxvf zookeeper-3.4.12.tar.gz
# cd zookeeper-3.4.12

Step3:重新命名配置檔案zoo_sample.cfg

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

Step4:啟動zookeeper

# bin/zkServer.sh start

Step5:檢測是否成功啟動,用zookeeper客戶端連線下服務端

# bin/zkCli.sh

 

Zookeeper使用


使用客戶端命令操作zookeeper


1、使用 ls 命令來檢視當前 ZooKeeper 中所包含的內容

[zk: localhost:2181(CONNECTED) 1] ls /
[dubbo, default, zookeeper]
[zk: localhost:2181(CONNECTED) 2] 

2、建立一個新的 znode ,使用 create /zkPro myData

[zk: localhost:2181(CONNECTED) 2] create /zkPro myData
Created /zkPro
[zk: localhost:2181(CONNECTED) 3] 

3、再次使用 ls 命令來檢視現在 zookeeper 中所包含的內容:

[zk: localhost:2181(CONNECTED) 3] ls /
[dubbo, default, zookeeper, zkPro]
[zk: localhost:2181(CONNECTED) 4] 

4、下面我們執行 get 命令來確認第二步中所建立的 znode 是否包含我們所建立的字串:

[zk: localhost:2181(CONNECTED) 6] get /zkPro      
myData
cZxid = 0x1146
ctime = Tue Sep 04 10:40:49 CST 2018
mZxid = 0x1146
mtime = Tue Sep 04 10:40:49 CST 2018
pZxid = 0x1146
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
[zk: localhost:2181(CONNECTED) 7] 

5、下面我們通過 set 命令來對 zk 所關聯的字串進行設定:

[zk: localhost:2181(CONNECTED) 7] set /zkPro myData123456
cZxid = 0x1146
ctime = Tue Sep 04 10:40:49 CST 2018
mZxid = 0x1147
mtime = Tue Sep 04 10:43:59 CST 2018
pZxid = 0x1146
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 12
numChildren = 0
[zk: localhost:2181(CONNECTED) 8]

6、下面我們將剛才建立的 znode 刪除

[zk: localhost:2181(CONNECTED) 8] delete /zkPro
[zk: localhost:2181(CONNECTED) 9] 

 

使用Java API操作zookeeper

使用Java API操作zookeeper需要引用下面的包



	com.101tec
	zkclient
	0.10

 

下面我們來實現上面說的分散式配置中心:

1、在zookeeper裡增加一個目錄節點,並且把配置資訊儲存在裡面

[zk: localhost:2181(CONNECTED) 9] create /username zhangsan
Created /username
[zk: localhost:2181(CONNECTED) 10]

2、啟動兩個zookeeper客戶端程式,程式碼如下所示

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
 *
 */
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("192.168.188.128: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) {
                }
            }
        }
    }
}

兩個程式啟動後都正確的讀取到了zookeeper的/username目錄節點下的資料'zhangsan'

3、我們在zookeeper裡修改下目錄節點/username下的資料

[zk: localhost:2181(CONNECTED) 10] set /username zhangsan123456
cZxid = 0x1149
ctime = Tue Sep 04 10:49:11 CST 2018
mZxid = 0x114a
mtime = Tue Sep 04 10:52:08 CST 2018
pZxid = 0x1149
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 14
numChildren = 0
[zk: localhost:2181(CONNECTED) 11] 

修改完成後,我們看見兩個程式後臺都及時收到了他們監聽的目錄節點資料變更後的值,如下所示:

zhangsan
配置已修改,新值為:zhangsan123456

 

Zookeeper叢集模式安裝


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

Step1:配置JAVA環境,檢驗環境:java -version

Step2:下載並解壓zookeeper

# cd /usr/local
# wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper-3.4.12.tar.gz
# tar -zxvf zookeeper-3.4.12.tar.gz
# cd zookeeper-3.4.12

Step3:重新命名 zoo_sample.cfg檔案

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

Step4:修改配置檔案zoo-1.cfg,原配置檔案裡有的,修改成下面的值,沒有的則加上

# vim conf/zoo-1.cfg
dataDir=/tmp/zookeeper-1
clientPort=2181
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890

配置說明

tickTime:這個時間是作為 Zookeeper 伺服器之間或客戶端與伺服器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發送一個心跳。
initLimit:這個配置項是用來配置 Zookeeper 接受客戶端(這裡所說的客戶端不是使用者連線 Zookeeper 伺服器的客戶端,而是 Zookeeper 伺服器叢集中連線到 Leader 的 Follower 伺服器)初始化連線時最長能忍受多少個心跳時間間隔數。當已經超過 10個心跳的時間(也就是 tickTime)長度後 Zookeeper 伺服器還沒有收到客戶端的返回資訊,那麼表明這個客戶端連線失敗。總的時間長度就是 10*2000=20 秒
syncLimit:這個配置項標識 Leader 與 Follower 之間傳送訊息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度,總的時間長度就是 5*2000=10秒
dataDir:顧名思義就是 Zookeeper 儲存資料的目錄,預設情況下,Zookeeper 將寫資料的日誌檔案也儲存在這個目錄裡。
clientPort:這個埠就是客戶端連線 Zookeeper 伺服器的埠,Zookeeper 會監聽這個埠,接受客戶端的訪問請求。
server.A=B:C:D:其中 A 是一個數字,表示這個是第幾號伺服器;B 是這個伺服器的 ip 地址;C 表示的是這個伺服器與叢集中的 Leader 伺服器交換資訊的埠;D 表示的是萬一叢集中的 Leader 伺服器掛了,需要一個埠來重新進行選舉,選出一個新的 Leader,而這個埠就是用來執行選舉時伺服器相互通訊的埠。如果是偽叢集的配置方式,由於 B 都是一樣,所以不同的 Zookeeper 例項通訊埠號不能一樣,所以要給它們分配不同的埠號。

Step5:再從zoo-1.cfg複製兩個配置檔案zoo-2.cfg和zoo-3.cfg,只需修改dataDir和clientPort不同即可

# cp conf/zoo-1.cfg conf/zoo-2.cfg
# cp conf/zoo-1.cfg conf/zoo-3.cfg
# vim conf/zoo-2.cfg
dataDir=/tmp/zookeeper-2
clientPort=2182
# vim conf/zoo-2.cfg
dataDir=/tmp/zookeeper-3
clientPort=2183

Step6:標識Server ID

建立三個資料夾/tmp/zookeeper-1,/tmp/zookeeper-2,/tmp/zookeeper-2,在每個目錄中建立檔案myid 檔案,寫入當前例項的server id,即1.2.3

# cd /tmp/zookeeper-1
# vim myid
1
# cd /tmp/zookeeper-2
# vim myid
2
# cd /tmp/zookeeper-3
# vim myid
3

Step7:啟動三個zookeeper例項

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

Step8:檢測叢集狀態,也可以直接用命令“zkCli.sh -server IP:PORT”連線zookeeper服務端檢測:

至此,我們對zookeeper就算有了一個入門的瞭解,當然zookeeper遠比我們這裡描述的功能多,比如用zookeeper實現叢集管理,分散式鎖,分散式佇列,zookeeper叢集leader選舉等等。