簡介
ZooKeeper 是一款分布式協調架構,它可以為分布式系統提供一緻性服務。ZooKeeper 最初由 Yahoo 開發,後來捐獻給了 Apache 基金會,現已成功 Apache 的頂級項目,目前在 Github 上有 9.5k+Star。
ZooKeeper 作為頂級分布式開源項目,應用非常廣泛,Dubbo 和 Kafka 這些知名的開源項目都在使用。
分布式協調
要了解 ZooKeeper 我們首先需要了解下什麼是
分布式協調
?這裡拿 Spring Cloud 中注冊中心的例子來說吧。
微服務(分布式)系統中有很多服務,相同的服務又有多個執行個體,我們在應用中可以通過服務名來負載均衡地調用服務,而這些服務有可能會挂掉,也有可能會有新的執行個體加入。此時我們就需要一個東西來做協調,儲存好服務名稱和可用執行個體調用 IP 的對應關系,此時注冊中心就是一個分布式協調者的角色,而 ZooKeeper 就可以用來充當這個協調者。
安裝
ZooKeeper 的安裝無論是 Windows 還是 Linux 都是很友善的,我們先來學習下它的安裝。
Windows 安裝
- 首先下載下傳 ZooKeeper 安裝包,下載下傳位址:https://www.apache.org/dyn/closer.lua/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7.0-bin.tar.gz
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iY4E2M5ImMyMjZyIWYyQGM5MWOmFDZxkjY4QmM3kDOh9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
- 解壓到指定目錄,解壓完成後目錄結構如下;
- 在
目錄下建立配置檔案conf
,内容如下;zoo.cfg
# 設定心跳時間,機關毫秒tickTime=2000# 存儲記憶體資料庫快照的檔案夾dataDir=I:/developer/env/apache-zookeeper-3.7.0-bin/data# 監聽用戶端連接配接的端口clientPort=2181
- 進入
目錄,啟動 ZooKeeper 服務;bin
zkServer.cmd<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">
- 服務啟動成功後,控制台會輸出如下資訊。
Linux 安裝
- 使用 Docker 安裝 ZooKeeper 無疑是最友善的,首先我們下載下傳它的 Docker 鏡像;
docker pull zookeeper:3.7.0<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">
- 建立好 ZooKeeper 的配置檔案目錄,并切換到該目錄建立配置檔案
;zoo.cfg
mkdir /mydata/zookeeper/conf/ -pcd /mydata/zookeeper/conf/touch zoo.cfg
- 配置檔案
内容如下,直接使用 VIM 編輯即可;zoo.cfg
# 設定心跳時間,機關毫秒tickTime=2000# 存儲記憶體資料庫快照的檔案夾dataDir=/tmp/zookeeper# 監聽用戶端連接配接的端口clientPort=2181
- 運作 ZooKeeper 容器。
docker run -p 2181:2181 --name zookeeper \<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">-v /mydata/zookeeper/conf/zoo.cfg:/conf/zoo.cfg \<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">-d zookeeper:3.7.0<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">
指令行操作
接下來我們用指令行來操作下 ZooKeeper,熟悉下 ZooKeeper 的使用。
- 首先使用
指令行工具連接配接到 ZooKeeper;zkCli
zkCli.cmd -server 127.0.0.1:2181<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">
- 通過
可以指令檢視 ZooKeeper 的常用指令;help
[zk: 127.0.0.1:2181(CONNECTED) 0] helpZooKeeper -server host:port -client-configuration properties-file cmd args addWatch [-m mode] path # optional mode is one of [PERSISTENT, PERSISTENT_RECURSIVE] - default is PERSISTENT_RECURSIVE addauth scheme auth close config [-c] [-w] [-s] connect host:port create [-s] [-e] [-c] [-t ttl] path [data] [acl] delete [-v version] path deleteall path [-b batch size] delquota [-n|-b|-N|-B] path get [-s] [-w] path getAcl [-s] path getAllChildrenNumber path getEphemerals path history listquota path ls [-s] [-w] [-R] path printwatches on|off quit reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*] redo cmdno removewatches path [-c|-d|-a] [-l] set [-s] [-v version] path data setAcl [-s] [-v version] [-R] path acl setquota -n|-b|-N|-B val path stat [-w] path sync path version whoami
- 大家都知道 Redis 是通過
的形式存儲資料的,而 ZooKeeper 是通過key-value
的形式存儲資料的,znode 有點像目錄,而znode-value
目錄就是 ZooKeeper 中的根目錄,通過如下指令可以檢視所有 znode;/
[zk: 127.0.0.1:2181(CONNECTED) 1] ls /<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">[zookeeper]<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">
- 建立一個 znode 叫做
,存儲字元串/zk_test
,這用起來有點像 Redis;my_data
[zk: 127.0.0.1:2181(CONNECTED) 2] create /zk_test my_data<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">Created /zk_test<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">
- 檢視所有 znode,可以看到
這個 znode;zk_test
[zk: 127.0.0.1:2181(CONNECTED) 3] ls /<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">[zk_test, zookeeper]<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">
- 擷取 znode 中存儲的資料;
[zk: 127.0.0.1:2181(CONNECTED) 4] get /zk_test<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">my_data<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">
- 修改 znode 中的資料;
[zk: 127.0.0.1:2181(CONNECTED) 5] set /zk_test test_data[zk: 127.0.0.1:2181(CONNECTED) 6] get /zk_testtest_data
- 删除 znode 中的資料;
[zk: 127.0.0.1:2181(CONNECTED) 7] delete /zk_test<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">[zk: 127.0.0.1:2181(CONNECTED) 8] ls /<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">[zookeeper]<br data-darkmode-color-16243305138977="rgb(171, 178, 191)" data-darkmode-original-color-16243305138977="#fff|rgb(0,0,0)|rgb(171, 178, 191)" data-darkmode-bgcolor-16243305138977="rgb(49, 54, 63)" data-darkmode-original-bgcolor-16243305138977="#fff|rgb(40, 44, 52)">
可視化管理
PrettyZoo
是一款基于 Apache Curator 和 JavaFX 實作的 Zookeeper 圖形化管理用戶端。顔值很高,推薦使用。
- 首先下載下傳
的安裝包,下載下傳位址:https://github.com/vran-dev/PrettyZoo/releasesPrettyZoo
- 我們需要建立一個連接配接,連接配接到 ZooKeeper,可以發現
是支援通過 SSH 通道連接配接的;PrettyZoo
- 輕按兩下連接配接,我們可以檢視到 ZooKeeper 中存儲的資料,很清楚的發現,ZooKeeper 是按目錄結構存儲資料的;
- 右鍵目錄,我們可以建立和删除 znode,有了這個工具,基本上可以和指令行操作說再見了;
- 如果你還是覺得指令行比較炫酷的話,
也實作了指令行功能,打開指令行标簽就可以愉快地敲指令了。PrettyZoo
節點類型
ZooKeeper 中的節點(znode)是有生命周期的,這取決于節點的類型。類型有主要有下面四種:
- 持久節點(Persistent):預設節點類型,節點建立後,會一直存在。
- 持久順序節點(Persistent Sequential):具有持久節點特性,節點名稱後會增加自增數字字尾。
- 臨時節點(Ephemeral):臨時存在,當建立節點的會話關閉時,節點被删除。
- 臨時順序節點(Ephemeral Sequential):具有臨時節點特性,節點名稱後會增加自增數字字尾。
如果你用指令行建立節點的話,順序特性對應
-s
選項,臨時特性對應
-e
選項,比如如下指令:
# 建立持久順序節點create -s /test/seq segText# 建立臨時節點create -e /test/tmp tmpText# 建立臨時順序節點create -s -e /test/seqTmp setTmpText
建立成功後顯示如下:
如果你用
PrettyZoo
來建立的話,隻要勾選一個選項即可。
作為注冊中心使用
CAP 是分布式架構中的重要理論,其包括一緻性 (Consistency)、可用性(Availability) 和分區容忍性(Partition tolerance)。我們經常使用的 Eureka 支援 AP,而 ZooKeeper 支援 CP。接下來我們學習下 ZooKeeper 在 Spring Cloud 中作為注冊中心的應用。
- ZooKeeper 作為注冊中心使用,用法基本和 Eureka 和 Consul 相同,首先我們需要在
中添加 ZooKeeper 的服務發現元件;pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId></dependency>
- 之後修改配置檔案
,添加 ZooKeeper 相關配置;application.yml
spring: cloud: zookeeper: # zookeeper連接配接位址 connect-string: localhost:2181 discovery: # 作為服務注冊 register: true # 注冊時使用IP位址而不是hostname prefer-ip-address: true
- 這裡還是使用《Spring Cloud 學習教程》中的例子,有兩個服務
和zookeeper-ribbon-service
,前者通過 Ribbon 遠端調用後者;zookeeper-user-service
- 分别啟動兩個服務,我們通過
可以發現,當 ZooKeeper 作為注冊中心時,注冊服務的名稱、IP、端口都被存儲到了裡面;PrettyZoo
- 我們調用
中的接口測試下,發現可以正常通路,接口位址:http://localhost:8301/user/1zookeeper-ribbon-service
- 如果這時候我們把
服務關掉的話,我們可以發現 ZooKeeper 會自動删除存儲的資料;zookeeper-user-service
- 由此可以看出,ZooKeeper 作為微服務的注冊中心是通過臨時節點來實作的,當服務上線時會向 ZooKeeper 中注冊,當服務下線時會被 ZooKeeper 删除,保障了微服務的高可用。
總結
今天我們學習了下 ZooKeeper 的安裝、可視化工具 PrettyZoo 的使用以及 ZooKeeper 在 Spring Cloud 中作為注冊中心的應用。其實 ZooKeeper 在分布式系統中還有很多應用,比如說做分布式鎖、實作選主功能、取代 UUID 來生成唯一 ID,大家感興趣的話可以深入研究下!
參考資料
官方文檔:https://zookeeper.apache.org/doc/current/zookeeperStarted.html
項目源碼位址
https://github.com/macrozheng/springcloud-learning