點贊再看他匪,養(yǎng)成習慣,微信搜一搜【一角錢小助手】 關(guān)注更多原創(chuàng)技術(shù)文章夸研。
本文 GitHub org_hejianhui/JavaStudy 已收錄邦蜜,有我的系列文章。
前言
對于做Java開發(fā)而言亥至,面試過程中肯定有聊到分布式系統(tǒng)悼沈,面試官跟你聊完 dubbo 相關(guān)一些問題之后,已經(jīng)確認你對分布式服務(wù)框架/RPC框架都有一些認知了姐扮,那么他很有可能開始要跟你聊分布式相關(guān)的其他問題了絮供。比如分布式鎖這個東西,很常用的茶敏。你做Java系統(tǒng)開發(fā)壤靶,分布式系統(tǒng)可能會有一些場景會用到。最常用的分布式鎖就是基于 zookeeper 來實現(xiàn)的惊搏。
因為 zookeeper 是分布式系統(tǒng)中很常見的一個基礎(chǔ)系統(tǒng)贮乳,而且面試常問的就是說 zookeeper 的使用場景是什么?看你知不知道這一些基本的使用場景恬惯。但其實 zookeeper 深挖可以問的很深很深的向拆。基于此我們來深入學習下 zookeeper酪耳,開始來寫 zookeeper 系列文章了浓恳,本篇重點介紹下 zookeeper 的特性和節(jié)點說明。
Zookeeper 背景
分布式
互聯(lián)網(wǎng)技術(shù)的發(fā)展碗暗,導致大型系統(tǒng)/網(wǎng)站需要的計算能力和存儲能力越來越高奖蔓。系統(tǒng)/網(wǎng)站架構(gòu)逐漸從集中式轉(zhuǎn)變成分布式。
什么是分布式
把一個計算任務(wù)分解為若干個計算單元讹堤,并分派到若干個不同的計算機中去執(zhí)行吆鹤,然后再匯總計算結(jié)果。
分布式的工作方式有點類似于團隊合作洲守。當有一項任務(wù)分配到某個團隊之后疑务,團隊內(nèi)部的成員開始各司其職,然后把工作結(jié)果統(tǒng)一匯總給團隊主管梗醇,由團隊主管再整理團隊的工作成果匯報給公司知允。
分布式存在的問題
雖然分布式和集中式系統(tǒng)相比有很多優(yōu)勢,比如能提供更強的計算叙谨、存儲能力温鸽,避免單點故障等問題。但是由于采用分布式部署的方式,就經(jīng)常會出現(xiàn)網(wǎng)絡(luò)故障等問題涤垫,并且如何在分布式系統(tǒng)中保證數(shù)據(jù)的一致性和可用性也是一個比較關(guān)鍵的問題姑尺。
比如在集中式系統(tǒng)中,有一些關(guān)鍵的配置信息蝠猬,可以直接保存在服務(wù)器的內(nèi)存中切蟋,但是在分布式系統(tǒng)中,如何保存這些配置信息榆芦,又如何保證所有機器上的配置信息都保持一致柄粹,又如何保證修改一個配置能夠把這次修改同步到所有機器中呢?
再比如匆绣,在集中式系統(tǒng)中驻右,進行一個同步操作要寫同一個數(shù)據(jù)的時候,可以直接使用事務(wù)+鎖來管理保證數(shù)據(jù)的ACID崎淳。但是堪夭,在分布式系統(tǒng)中如何保證多臺機器不會同時寫同一條數(shù)據(jù)呢?
Zookeeper產(chǎn)生背景
項目從單體到分布式轉(zhuǎn)變之后凯力,將會產(chǎn)生多個節(jié)點之間協(xié)同的問題茵瘾。如:
- 每天的定時任務(wù)由誰哪個節(jié)點來執(zhí)行?
- RPC調(diào)用時的服務(wù)發(fā)現(xiàn)?
- 如何保證并發(fā)請求的冪等
- ....
這些問題可以統(tǒng)一歸納為多節(jié)點協(xié)調(diào)問題咐鹤,如果靠節(jié)點自身進行協(xié)調(diào)這是非常不可靠的拗秘,性能上也不可取。必須由一個獨立的服務(wù)做協(xié)調(diào)工作祈惶,它必須可靠雕旨,而且保證性能。
Zookeeper 介紹
Zookeeper 的由來
2006年的時候Google出了Chubby來解決分布一致性的問題(distributed consensus problem)捧请,所有集群中的服務(wù)器通過Chubby最終選出一個Master Server 凡涩,最后這個Master Server來協(xié)調(diào)工作。簡單來說其原理就是:在一個分布式系統(tǒng)中疹蛉,有一組服務(wù)器在運行同樣的程序活箕,它們需要確定一個Value,以那個服務(wù)器提供的信息為主/為準可款,當這個服務(wù)器經(jīng)過n/2+1的方式被選出來后育韩,所有的機器上的Process都會被通知到這個服務(wù)器就是主服務(wù)器 Master服務(wù)器,大家以他提供的信息為準闺鲸。很想知道Google Chubby中的奧妙筋讨,可惜人家Google不開源,自家用摸恍。
但是在2009年3年以后沉默已久的Yahoo在Apache上推出了類似的產(chǎn)品ZooKeeper悉罕,并且在Google原有Chubby的設(shè)計思想上做了一些改進,因為ZooKeeper并不是完全遵循Paxos協(xié)議,而是基于自身設(shè)計并優(yōu)化的一個2 phase commit的協(xié)議壁袄。
下面這段內(nèi)容摘自《從Paxos到Zookeeper 》第四章第一節(jié)的某段內(nèi)容类早,推薦大家閱讀以下:
Zookeeper最早起源于雅虎研究院的一個研究小組。在當時然想,研究人員發(fā)現(xiàn)莺奔,在雅虎內(nèi)部很多大型系統(tǒng)基本都需要依賴一個類似的系統(tǒng)來進行分布式協(xié)調(diào)欣范,但是這些系統(tǒng)往往都存在分布式單點問題变泄。所以,雅虎的開發(fā)人員就試圖開發(fā)一個通用的無單點問題的分布式協(xié)調(diào)框架恼琼,以便讓開發(fā)人員將精力集中在處理業(yè)務(wù)邏輯上妨蛹。關(guān)于“ZooKeeper”這個項目的名字,其實也有一段趣聞晴竞。在立項初期蛙卤,考慮到之前內(nèi)部很多項目都是使用動物的名字來命名的(例如著名的Pig項目),雅虎的工程師希望給這個項目也取一個動物的名字。時任研究院的首席科學家RaghuRamakrishnan開玩笑地說:“在這樣下去噩死,我們這兒就變成動物園了颤难!”此話一出,大家紛紛表示就叫動物園管理員吧一一一因為各個以動物命名的分布式組件放在一起已维, 雅虎的整個分布式系統(tǒng)看上去就像一個大型的動物園了行嗤,而Zookeeper正好要用來進行分布式環(huán)境的協(xié)調(diào)一一于是,Zookeeper的名字也就由此誕生了垛耳。
ZooKeeper 概覽
ZooKeeper 是一個開源的分布式協(xié)調(diào)服務(wù)栅屏,ZooKeeper 框架最初是在“Yahoo!"上構(gòu)建的,用于以簡單而穩(wěn)健的方式訪問他們的應(yīng)用程序堂鲜。
后來栈雳,Apache ZooKeeper 成為 Hadoop,HBase 和其他分布式框架使用的有組織服務(wù)的標準缔莲。
例如哥纫,Apache HBase 使用 ZooKeeper 跟蹤分布式數(shù)據(jù)的狀態(tài)。
ZooKeeper 的設(shè)計目標是將那些復雜且容易出錯的分布式一致性服務(wù)封裝起來痴奏,構(gòu)成一個高效可靠的原語集蛀骇,并以一系列簡單易用的接口提供給用戶使用。
原語: 操作系統(tǒng)或計算機網(wǎng)絡(luò)用語范疇抛虫。它是由若干條指令組成的松靡,用于完成一定功能的一個過程。具有不可分割性建椰,即原語的執(zhí)行必須是連續(xù)的雕欺,在執(zhí)行過程中不允許被中斷。
ZooKeeper 是一個典型的分布式數(shù)據(jù)一致性解決方案,分布式應(yīng)用程序可以基于 ZooKeeper 實現(xiàn)諸如數(shù)據(jù)發(fā)布/訂閱屠列、負載均衡囊咏、命名服務(wù)、分布式協(xié)調(diào)/通知瓢阴、集群管理咐蚯、Master 選舉、分布式鎖和分布式隊列等功能苛让。
ZooKeeper 一個最常用的使用場景就是用于擔任服務(wù)生產(chǎn)者和服務(wù)消費者的注冊中心沟蔑。
服務(wù)生產(chǎn)者將自己提供的服務(wù)注冊到 ZooKeeper 中心,服務(wù)的消費者在進行服務(wù)調(diào)用的時候先到 ZooKeeper 中查找服務(wù)狱杰,獲取到服務(wù)生產(chǎn)者的詳細信息之后瘦材,再去調(diào)用服務(wù)生產(chǎn)者的內(nèi)容與數(shù)據(jù)。
如下圖所示仿畸,在 Dubbo 架構(gòu)中 ZooKeeper 就擔任了注冊中心這一角色食棕。
- Provider: 暴露服務(wù)的提供方,可以通過jar或者容器的方式啟動服務(wù)
- Consumer:調(diào)用遠程服務(wù)的服務(wù)消費方错沽。
- Registry: 服務(wù)注冊中心和發(fā)現(xiàn)中心簿晓。
- Monitor: 統(tǒng)計服務(wù)和調(diào)用次數(shù),調(diào)用時間監(jiān)控中心千埃。(dubbo的控制臺頁面中可以顯示憔儿,目前只有一個簡單版本)
- Container:服務(wù)運行的容器。
znode 節(jié)點
Zookeeper 中數(shù)據(jù)基本單元叫節(jié)點镰禾,節(jié)點之下可包含子節(jié)點皿曲,最后以樹級方式程現(xiàn)。每個節(jié)點擁有唯一的路徑path吴侦∥菪荩客戶端基于PATH上傳節(jié)點數(shù)據(jù),Zookeeper 收到后會實時通知對該路徑進行監(jiān)聽的客戶端备韧。
部署與常規(guī)配置
Zookeeper 基于JAVA開發(fā)劫樟,下載后只要有對應(yīng)JVM環(huán)境即可運行。其默認的端口號是2181運行前得保證其不沖突织堂。
版本說明
2020年9月9日發(fā)行的3.6.2版是目前最新的一個穩(wěn)定版本叠艳。
另外在2020年9月9日發(fā)行的3.5.5是3.5分支的第一個穩(wěn)定版本。此版本被認為是3.4穩(wěn)定分支的后續(xù)版本易阳,可以用于生產(chǎn)附较。基于3.4它包含以下新功能
- 動態(tài)重新配置
- 本地會議
- 新節(jié)點類型:容器潦俺,TTL
- 原子廣播協(xié)議的SSL支持
- 刪除觀察者的能力
- 多線程提交處理器
- 升級到Netty 4.1
- Maven構(gòu)建
另請注意:建議的最低JDK版本為1.8
文件說明:
- apache-zookeeper-xxx-tar.gz 代表源代碼
- apache-zookeeper-xxx-bin.tar.gz 運行版本
下載地址:https://zookeeper.apache.org/releases.html#download
具體部署流程:
#下載
wget https://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.6.2/apache-zookeeper-3.6.2-bin.tar.gz
#解壓
tar -zxvf apache-zookeeper-3.6.2-bin.tar.gz
#拷貝默認配置
cd {zookeeper_home}/conf
cp zoo_sample.cfg zoo.cfg
#啟動
./zkServer.sh start
#關(guān)閉服務(wù)器
./zkServer.sh stop
#啟動客戶端
./zkCli.sh -server 127.0.0.1:2181
常規(guī)配置文件說明
# zookeeper時間配置中的基本單位 (毫秒)
tickTime=2000
# 允許follower初始化連接到leader最大時長拒课,它表示tickTime時間倍數(shù) 即:initLimit*tickTime
initLimit=10
# 允許follower與leader數(shù)據(jù)同步最大時長,它表示tickTime時間倍數(shù)
syncLimit=5
#zookeper 數(shù)據(jù)存儲目錄
dataDir=/tmp/zookeeper
#對客戶端提供的端口號
clientPort=2181
#單個客戶端與zookeeper最大并發(fā)連接數(shù)
maxClientCnxns=60
# 保存的數(shù)據(jù)快照數(shù)量徐勃,之外的將會被清除
autopurge.snapRetainCount=3
#自動觸發(fā)清除任務(wù)時間間隔,小時為單位早像。默認為0僻肖,表示不自動清除。
autopurge.purgeInterval=1
客戶端命令
系統(tǒng)命令
配置命令
節(jié)點命令
配額命令
權(quán)限命令
監(jiān)視器命令
node數(shù)據(jù)的增刪改查
# 列出子節(jié)點
ls /
#創(chuàng)建節(jié)點
create /hjh "hjh is good man"
# 查看節(jié)點
get /hjh
# 創(chuàng)建子節(jié)點
create /hjh/sex "man"
# 刪除節(jié)點
delete /hjh/sex
# 刪除所有節(jié)點 包括子節(jié)點
deleteall /hjh
Zookeeper節(jié)點介紹
Zookeeper 中節(jié)點叫 znode 存儲結(jié)構(gòu)上跟文件系統(tǒng)類似卢鹦,以樹級結(jié)構(gòu)進行存儲臀脏。不同之外在于znode沒有目錄的概念,不能執(zhí)行類似cd之類的命令冀自。znode結(jié)構(gòu)包含如下:
- path:唯一路徑
- childNode:子節(jié)點
- stat:狀態(tài)屬性
- type:節(jié)點類型
節(jié)點類型
- PERSISTENT(持久節(jié)點)
持久化保存的節(jié)點揉稚,也是默認創(chuàng)建的
#默認創(chuàng)建的就是持久節(jié)點
create /test
- PERSISTENT_SEQUENTIAL(持久序號節(jié)點)
創(chuàng)建時zookeeper 會在路徑上加上序號作為后綴,凡纳。非常適合用于分布式鎖窃植、分布式選舉等場景帝蒿。創(chuàng)建時添加 -s 參數(shù)即可荐糜。
#創(chuàng)建序號節(jié)點
create -s /test
#返回創(chuàng)建的實際路徑
Created /test0000000001
create -s /test
#返回創(chuàng)建的實際路徑2
Created /test0000000002
- EPHEMERAL(臨時節(jié)點)
臨時節(jié)點會在客戶端會話斷開后自動刪除。適用于心跳葛超,服務(wù)發(fā)現(xiàn)等場景暴氏。創(chuàng)建時添加參數(shù)-e 即可。
#創(chuàng)建臨時節(jié)點绣张, 斷開會話 在連接將會自動刪除
create -e /temp
- EPHEMERAL_SEQUENTIAL(臨時序號節(jié)點)
與持久序號節(jié)點類似答渔,不同之處在于EPHEMERAL_SEQUENTIAL是臨時的會在會話斷開后刪除。創(chuàng)建時添加 -e -s
create -e -s /seq
節(jié)點屬性
# 查看節(jié)點屬性
stat /test
其屬性說明如下表:
#創(chuàng)建節(jié)點的事物ID
cZxid = 0x8
#創(chuàng)建時間
ctime = Sat Oct 03 22:20:27 CST 2020
#修改節(jié)點的事物ID
mZxid = 0x8
#最后修改時間
mtime = Sat Oct 03 22:20:27 CST 2020
# 子節(jié)點變更的事物ID
pZxid = 0x8
#這表示對此znode的子節(jié)點進行的更改次數(shù)(不包括子節(jié)點)
cversion = 0
# 數(shù)據(jù)版本侥涵,變更次數(shù)
dataVersion = 0
#權(quán)限版本沼撕,變更次數(shù)
aclVersion = 0
#臨時節(jié)點所屬會話ID
ephemeralOwner = 0x0
#數(shù)據(jù)長度
dataLength = 0
#子節(jié)點數(shù)(不包括子子節(jié)點)
numChildren = 0
節(jié)點的監(jiān)聽
客戶添加 -w 參數(shù)可實時監(jiān)聽節(jié)點與子節(jié)點的變化,并且實時收到通知芜飘。非常適用保障分布式情況下的數(shù)據(jù)一致性务豺。其使用方式如下:
acl權(quán)限設(shè)置
ACL全稱為Access Control List(訪問控制列表),用于控制資源的訪問權(quán)限嗦明。ZooKeeper使用ACL來控制對其znode的防問笼沥。基于 scheme:id:permission
的方式進行權(quán)限控制娶牌。scheme表示授權(quán)模式奔浅、id模式對應(yīng)值、permission即具體的增刪改權(quán)限位诗良。
scheme:認證模型
permission權(quán)限位
acl 相關(guān)命令
world權(quán)限示例
語法: setAcl world:anyone:<權(quán)限位>
注:world模式中anyone是唯一的值,表示所有人
- 查看默認節(jié)點權(quán)限:
#創(chuàng)建一個節(jié)點
create -e /testAcl
#查看節(jié)點權(quán)限
getAcl /testAcl
#返回的默認權(quán)限表示 汹桦,所有人擁有所有權(quán)限。
'world,'anyone: cdrwa
- 修改默認權(quán)限為 讀寫
#設(shè)置為rw權(quán)限
setAcl /testAcl world:anyone:rw
# 可以正常讀
get /testAcl
# 無法正常創(chuàng)建子節(jié)點
create -e /testAcl/t "hi"
# 返回沒有權(quán)限的異常
Authentication is not valid : /testAcl/t
IP權(quán)限示例
語法: setAcl ip:<ip地址|地址段>:<權(quán)限位>
auth模式示例
語法:
- setAcl auth:<用戶名>:<密碼>:<權(quán)限位>
- addauth digest <用戶名>:<密碼>
digest 權(quán)限示例
語法:
- setAcl digest :<用戶名>:<密鑰>:<權(quán)限位>
- addauth digest <用戶名>:<密碼>
注1:密鑰 通過sha1與base64組合加密碼生成鉴裹,可通過以下命令生成
echo -n <用戶名>:<密碼> | openssl dgst -binary -sha1 | openssl base64
注2:為節(jié)點設(shè)置digest 權(quán)限后舞骆,訪問前必須執(zhí)行addauth灵嫌,當前會話才可以防問。
- 設(shè)置digest 權(quán)限
#先 sha1 加密葛作,然后base64加密
echo -n hjh:123456 | openssl dgst -binary -sha1 | openssl base64
#返回密鑰
Td6f6IYc3Kjci9RQP1A6WzjkZv8=
#設(shè)置digest權(quán)限
setAcl /hjh digest:hjh:Td6f6IYc3Kjci9RQP1A6WzjkZv8=:cdrw
- 查看節(jié)點將顯示沒有權(quán)限
#查看節(jié)點
get /hjh
#顯示沒有權(quán)限訪問
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /hjh
- 給當前會話添加認證后再次查看
#給當前會話添加權(quán)限帳戶
addauth digest hjh:123456
#在次查看
get /hjh
#獲得返回結(jié)果
hjh is good man
ACL的特殊說明:
權(quán)限僅對當前節(jié)點有效寿羞,不會讓子節(jié)點繼承。如限制了IP防問A節(jié)點赂蠢,但不妨礙該IP防問A的子節(jié)點 /A/B绪穆。
Zookeeper 系列文章,敬請關(guān)注虱岂,下篇繼續(xù)玖院!