本篇內(nèi)容主要講解“ZooKeeper集群的數(shù)據(jù)同步過程是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“ZooKeeper集群的數(shù)據(jù)同步過程是什么”吧!
創(chuàng)新互聯(lián)主營(yíng)嘉蔭網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都App制作,嘉蔭h5微信平臺(tái)小程序開發(fā)搭建,嘉蔭網(wǎng)站營(yíng)銷推廣歡迎嘉蔭等地區(qū)企業(yè)咨詢
經(jīng)歷了選舉之后,我們的馬果果榮耀當(dāng)選當(dāng)前辦事處集群的 Leader,所以現(xiàn)在假設(shè)各個(gè)辦事處的關(guān)系圖是這樣:
我們現(xiàn)在就來說說馬小云和馬小騰是如何同馬果果進(jìn)行數(shù)據(jù)同步的。
結(jié)束了累人的選舉后,馬小云和馬小騰以微弱的優(yōu)勢(shì)輸?shù)袅烁?jìng)爭(zhēng),只能委屈成為 Follower。整理完各自的情緒后,他們要做的第一件事情就是通過話務(wù)員上報(bào)自己的信息給馬果果,使用了專門的暗號(hào) FOLLOWERINFO, 數(shù)據(jù)主要有自己的 epoch 和 myid:
然后是馬果果這邊,他收到 FOLLOWERINFO 之后也會(huì)進(jìn)行統(tǒng)計(jì),直到達(dá)到半數(shù)以上后,綜合各個(gè) Follower 給的信息會(huì)計(jì)算出新的 epoch,然后將這個(gè)新的 epoch 隨著暗號(hào) LEADERINFO 回發(fā)給其他 Follower
然后再回到馬小云和馬小騰這邊,收到 LEADERINFO 之后將新的 epoch 記錄下來,然后回復(fù)給馬果果一個(gè) ACKEPOCH 暗號(hào)并帶上自己這邊的最大 zxid,表示剛剛的 LEADERINFO 收到了
然后馬果果這邊也會(huì)等待半數(shù)以上的 ACKEPOCH 的通知,收到之后會(huì)根據(jù)各個(gè) Follower 的信息給出不同的同步策略。關(guān)于不同的同步策略,這里我先入為主的給大家介紹一下:
DIFF,如果 Follower 的記錄和 Leader 的記錄相差的不多,使用增量同步的方式將一個(gè)一個(gè)寫請(qǐng)求發(fā)送給 Follower
TRUNC,這個(gè)情況的出現(xiàn)代表 Follower 的 zxid 是領(lǐng)先于當(dāng)前的 Leader 的(可能是以前的 Leader),需要 Follower 自行把多余的部分給截?cái)?,降?jí)到和 Leader 一致
SNAP,如果 Follower 的記錄和當(dāng)前 Leader 相差太多,Leader 直接將自己的整個(gè)內(nèi)存數(shù)據(jù)發(fā)送給 Follower
至于采用哪一種策略,是如何進(jìn)行判斷的,接下來一一進(jìn)行講解。
每一個(gè) ZK 節(jié)點(diǎn)在收到寫請(qǐng)求后,會(huì)維護(hù)一個(gè)寫請(qǐng)求隊(duì)列(默認(rèn)是 500 大小,通過 zookeeper.commitLogCount
配置),將寫請(qǐng)求記錄在其中,這個(gè)隊(duì)列中的最早進(jìn)入的寫請(qǐng)求當(dāng)時(shí)的 zxid 就是 minZxid(以下簡(jiǎn)稱 min),最后一個(gè)進(jìn)入的寫請(qǐng)求的 zxid 就是 maxZxid(以下簡(jiǎn)稱 max),達(dá)到上限后,會(huì)移除最早進(jìn)入的寫請(qǐng)求,知道了這兩個(gè)值之后,我們來看看 DIFF 是怎么判斷的。
一種情況就是如果當(dāng) Follower 通過 ACKEPOCH 上報(bào)的 zxid 是在 min 和 max 之間的話,就采用 DIFF 策略進(jìn)行數(shù)據(jù)同步。
我們的例子中 Leader 的 zxid 是 99,說明這個(gè)存儲(chǔ) 500 個(gè)寫請(qǐng)求的隊(duì)列根本沒有放滿,所以 min 是 1 max 是 99,很顯然 77 以及 88 是在這個(gè)區(qū)間內(nèi)的,那馬果果就會(huì)為另外兩位 Follower 找到他們各自所需要的區(qū)間,先發(fā)送一個(gè) DIFF 給 Follower,然后將一條條的寫請(qǐng)求包裝成 PROPOSAL 和 COMMIT 的順序發(fā)給他們
另一種情況是如果 Follower 的 zxid 不在 min 和 max 的區(qū)間內(nèi)時(shí),但當(dāng) zookeeper.snapshotSizeFactor
配置大于 0 的話(默認(rèn)是 0.33),會(huì)嘗試使用 log 進(jìn)行 DIFF,但是需要同步的 log 文件的總大小不能超過當(dāng)前最新的 snapshot 文件大小的三分之一(以默認(rèn) 0.33 為例)的話,才可以通過讀取 log 文件中的寫請(qǐng)求記錄進(jìn)行 DIFF 同步。同步的方法也和上面一樣,先發(fā)送一個(gè) DIFF 給 Follower 然后從 log 文件中找到該 Follower 的區(qū)間,再一條條的發(fā)送 PROPOSAL 和 COMMIT。
而 Follower 收到 PROPOSAL 的暗號(hào)消息后,就會(huì)像處理客戶端請(qǐng)求那樣去一條條處理,慢慢就會(huì)將數(shù)據(jù)恢復(fù)成和 Leader 是一致的。
假設(shè)現(xiàn)在三個(gè)辦事處是這樣的
馬果果的寫請(qǐng)求隊(duì)列在默認(rèn)配置下記錄了 277 至 777 的寫請(qǐng)求,又假設(shè)現(xiàn)在的場(chǎng)景不滿足上面 1.1.2 的情況,馬果果就知道當(dāng)前需要通過 SNAP 的情況進(jìn)行同步了。
馬果果會(huì)先發(fā)送一個(gè) SNAP 的請(qǐng)求給馬小云和馬小騰讓他們準(zhǔn)備起來
緊接著就會(huì)當(dāng)前內(nèi)存中的數(shù)據(jù)整個(gè)序列化(和 snapshot 文件是一樣的)然后一起發(fā)送給馬小云和馬小騰。
而馬小云和馬小騰收到馬果果發(fā)來的整個(gè) snapshot 之后會(huì)先清空自己當(dāng)前的數(shù)據(jù)庫(kù)的所有信息,接著直接將收到的 snapshot 反序列化就完成了整個(gè)內(nèi)存數(shù)據(jù)的恢復(fù)。
最后一種策略的場(chǎng)景假設(shè)是這樣:
假設(shè)馬小騰是上一個(gè) Leader,但是經(jīng)歷了停電以后恢復(fù)重新以 Follower 的身份加入集群,但是他的 zxid 要比 max 還大,這個(gè)時(shí)候馬果果就會(huì)給馬小騰發(fā)送 TRUNC,(至于圖中為什么馬小云不舉例為 TRUNC,因?yàn)槿绻?strong>馬小云的 zxid 也比馬果果要大的話,馬果果在當(dāng)前場(chǎng)景下就不可能當(dāng)選 Leader 了)。
馬果果就會(huì)發(fā)送 TRUNC 給馬小騰(這里忽略馬小云)
假設(shè)馬小騰的本地 log 文件目錄下是這樣的:
/tmp └── zookeeper └── log └── version-2 └── log.0 └── log.500 └── log.800
而馬小騰收到 TRUNC 之后,會(huì)找到本地 log 文件中所有大于 777 的 log 文件刪除,即這里的 log.800
,然后會(huì)在 log.500
這個(gè)文件找到 777 這個(gè) zxid 記錄并且把當(dāng)前文件的讀寫指針修改至 777 的位置,之后針對(duì)該文件的讀寫操作就會(huì)從 777 開始,這樣就會(huì)把之后的那些記錄給覆蓋了。
而馬果果這邊當(dāng)判斷完同步策略并發(fā)送給另外兩馬之后,便會(huì)發(fā)送一個(gè) NEWLEADER 的信息給他們
而馬小云和馬小騰在收到 NEWLEADER 之后,若之前是通過 SNAP 方式同步數(shù)據(jù)的話,這里會(huì)強(qiáng)制快照一份新的 snapshot 文件在自己這里。然后會(huì)回復(fù)給馬果果一個(gè) ACK 的消息,告訴他自己的同步數(shù)據(jù)已經(jīng)完成了
然后馬果果同樣會(huì)等待半數(shù)一樣的 ACK 接收完成后,再發(fā)送一個(gè) UPTODATE 給其他兩馬,告訴他們現(xiàn)在辦事處數(shù)據(jù)已經(jīng)都一致了,可以開始對(duì)外提供服務(wù)了
然后馬小云和馬果果收到 UPTODATE 之后會(huì)再回復(fù)一個(gè) ACK 給馬果果,但是這次馬果果收到這次的 ACK 之后不會(huì)做處理,所以在 UPTODATE 之后,各個(gè)辦事處就已經(jīng)算可以正式對(duì)外提供服務(wù)了。
上面說了這么多,但是馬小云和馬小騰都是 Follower,如果是 Observer 呢?怎么用上面的步驟同步呢?
區(qū)別就在第一步,F(xiàn)ollower 發(fā)送的是 FOLLOWERINFO,而 Observer 發(fā)送的是 OBSERVERINFO 除此之外沒有任何區(qū)別,和 Follower 是一樣的步驟進(jìn)行數(shù)據(jù)同步。
現(xiàn)在把其中的一些細(xì)節(jié)再用猿話說明一下,三種不同的數(shù)據(jù)同步策略,Leader 在發(fā)送 Follower 的時(shí)候采用的具體方法是不太相同的
如果采用的是 DIFF 或者 TRUNC 的同步方法的話,Leader 其實(shí)不是在找到有差異數(shù)據(jù)的時(shí)候發(fā)送過去的,而是按照順序先放入一個(gè)隊(duì)列,最后再統(tǒng)一啟動(dòng)一個(gè)線程去一個(gè)個(gè)發(fā)送的
DIFF :
TRUNC:
但是以 SNAP 方式同步的話就不會(huì)放入該隊(duì)列,無論是 SNAP 消息還是之后整個(gè)序列化后的內(nèi)存快照 snapshot 都會(huì)直接通過服務(wù)端間的 socket 直接寫入。
讓我們把三種策略消息交互的全過程再看一遍,這里就以馬小云舉例了
可以看到首尾是一樣的,就是中間的請(qǐng)求根據(jù)不同的策略會(huì)有不同的請(qǐng)求發(fā)送。差不多到這里關(guān)于 Follower 或 Observer 是如何同 Leader 同步消息,整體的邏輯都介紹完了。
Follower 和 Observer 同步數(shù)據(jù)的方式一共有三種:DIFF、SNAP、TRUNC
DIFF 需要 Follower 或 Observer 和 Leader 的數(shù)據(jù)相差在 min 和 max 范圍內(nèi),或者配置了允許從 log 文件中恢復(fù)
TRUNC 是當(dāng) Follower 或 Observer 的 zxid 比 Leader 還要大的時(shí)候,該節(jié)點(diǎn)需要主動(dòng)刪除多余 zxid 相關(guān)的數(shù)據(jù),降級(jí)至 Leader 一致
SNAP 作為最后的數(shù)據(jù)同步手段,由 Leader 直接將內(nèi)存數(shù)據(jù)整個(gè)序列化完并發(fā)送給 Follower 或 Observer,以達(dá)到恢復(fù)數(shù)據(jù)的目的
我看了下文章的字?jǐn)?shù)還行,決定加一點(diǎn)料,開一個(gè)小篇講一下 ACL,這個(gè)我拖了很久沒解釋的坑。
先帶大家重拾記憶,之前創(chuàng)建節(jié)點(diǎn)代碼片段中的 ZooDefs.Ids.OPEN_ACL_UNSAFE
就是 ACL 的參數(shù)
client.create("/更新視頻/跳舞/20201101", "這是Data,既可以記錄一些業(yè)務(wù)數(shù)據(jù)也可以隨便寫".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
首先如果配置了 zookeeper.skipACL
該參數(shù)為 yes
(注意大小寫),表示當(dāng)前節(jié)點(diǎn)放棄 ACL 校驗(yàn),默認(rèn)是 no
那這個(gè) ACL 是怎么規(guī)定的,有哪些權(quán)限,又是怎么在服務(wù)端體現(xiàn)的呢?首先 ACL 整體分為 Permission 和 Scheme 兩部分,Permission 是針對(duì)操作的權(quán)限,而 Scheme 是指定使用哪一種鑒權(quán)模式,下面我們一起來了解下。
首先 ZK 將權(quán)限分為 5 種:
READ(以下簡(jiǎn)稱 R),獲取節(jié)點(diǎn)數(shù)據(jù)或者獲取子節(jié)點(diǎn)列表
WRITE(以下簡(jiǎn)稱 W),設(shè)置節(jié)點(diǎn)數(shù)據(jù)
CREATE(以下簡(jiǎn)稱 C),創(chuàng)建節(jié)點(diǎn)
DELETE(以下簡(jiǎn)稱 D),刪除節(jié)點(diǎn)
ADMIN(以下簡(jiǎn)稱 A),設(shè)置節(jié)點(diǎn)的 ACL 權(quán)限
然后該 5 種權(quán)限在代碼層面就是簡(jiǎn)單的 int 數(shù)據(jù),而判斷是否有權(quán)限只需要用 & 操作即可,和目標(biāo)權(quán)限 & 完結(jié)果只要不等于 0 就說明擁有該權(quán)限,細(xì)節(jié)如下:
int binary R 1 00001 W 2 00010 C 4 00100 D 8 01000 A 16 10000
假設(shè)現(xiàn)在的客戶端權(quán)限為 RWC,對(duì)應(yīng)的數(shù)值就是各個(gè)權(quán)限相加 1 + 2 + 4 = 7
int binary RWC 7 00111
對(duì)任意有 R、W、C 權(quán)限需求的節(jié)點(diǎn),求 & 的結(jié)果都不為 0,所以就能判斷該客戶端是擁有 RWC 這 3 個(gè)權(quán)限的。
但是如果當(dāng)該客戶端對(duì)目標(biāo)節(jié)點(diǎn)進(jìn)行刪除時(shí),做 & 判斷權(quán)限的話,可以得到結(jié)果為 0,表示該客戶端不具備刪除的權(quán)限,就會(huì)返回給客戶端權(quán)限錯(cuò)誤
int binary RWC 7 00111 D 8 & 01000 ------------------ 結(jié)果 0 00000
Scheme 有 4 種,分別是 ip
、world
、digest
、super
,但是其實(shí)就是兩大類,一種是針對(duì) IP 地址的 ip,另一種是使用類似“用戶名:密碼”的 world
、digest
、super
。其實(shí)整個(gè) ACL 是分三個(gè)部分的,scheme:id:perms
,id 的取值取決于 scheme 的種類,這里是 ip 所以 id 的取值就是具體的 IP 地址,而 perms 則是我上一小節(jié)介紹的 RWCDA。
這三部分的前兩部分 scheme:id
相當(dāng)于告訴服務(wù)端 “我是誰?”,而最后的部分 perms
則是代表了 “我能做什么?”,這兩個(gè)問題,任意一個(gè)問題出錯(cuò)都會(huì)導(dǎo)致服務(wù)端拋出 NoAuthException
的異常,告訴客戶端權(quán)限不夠。
我們先來直接看一段代碼,其中的 IP 10.11.12.13
我是隨便寫的
ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null); List<acl> aclList = new ArrayList<>(); aclList.add(new ACL(ZooDefs.Perms.ALL, new Id("ip", "10.11.12.13"))); String path = client.create("/abc", "test".getBytes(), aclList, CreateMode.PERSISTENT); System.out.println(path); // 輸出 /abc client.close();
可以看到 /abc
是可以被正確輸出的,而且通過查看 /
的子節(jié)點(diǎn)列表是可以看到 /abc
節(jié)點(diǎn)的
ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null); List<string> children = client.getChildren("/", false); System.out.println(children); // 輸出 [abc, zookeeper] client.close();
但是現(xiàn)在如果去訪問該節(jié)點(diǎn)的數(shù)據(jù)的話就會(huì)得到報(bào)錯(cuò)
ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null); byte[] data = client.getData("/abc", false, null); System.out.println(new String(data)); client.close();
Exception in thread "main" org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /abc
讀者可以試試把上面的 IP 改成 127.0.0.1
重新創(chuàng)建節(jié)點(diǎn),之后就能正常訪問了,一般生產(chǎn)環(huán)境中 IP 模式用的不多(也可能是我用的不多),如果要用 IP 控制訪問的話,通過防火墻白名單之類的手段即可,這個(gè)層面我認(rèn)為不需要 ZK 去管。
這個(gè)模式應(yīng)該是最常用的(手動(dòng)狗頭)
我們還是來看一段代碼
ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null); List<acl> aclList = new ArrayList<>(); aclList.add(new ACL(ZooDefs.Perms.READ, new Id("world", "anyone"))); // 區(qū)別是這行 String path = client.create("/abc", "test".getBytes(), aclList, CreateMode.PERSISTENT); System.out.println(path); // 輸出 /abc client.close();
我把 scheme 改成了 World 模式,而 World 模式的 id 取值就是固定的 anyone 不能用其他值,而且我還設(shè)置了 perms 為 R,所以這個(gè)節(jié)點(diǎn)只能讀數(shù)據(jù),但不能做其他操作,如果使用 setData
對(duì)其進(jìn)行數(shù)據(jù)修改的話也會(huì)得到權(quán)限的錯(cuò)誤
ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null); Stat stat = client.setData("/abc", "newData".getBytes(), -1); // NoAuth for /abc
現(xiàn)在再回頭看之前的 ZooDefs.Ids.OPEN_ACL_UNSAFE
,其實(shí)就是 ZK 提供的常用的靜態(tài)常量,代表不校驗(yàn)權(quán)限
Id ANYONE_ID_UNSAFE = new Id("world", "anyone"); ArrayList<acl> OPEN_ACL_UNSAFE = new ArrayList<acl>(Collections.singletonList(new ACL(Perms.ALL, ANYONE_ID_UNSAFE)));
這個(gè)就是我們熟悉的用戶名密碼了,還是先上代碼
ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null); List<acl> aclList = new ArrayList<>(); aclList.add(new ACL(ZooDefs.Perms.ALL, new Id("digest", DigestAuthenticationProvider.generateDigest("laoxun:kaixin")))); // 1 String path = client.create("/abc", "test".getBytes(), aclList, CreateMode.PERSISTENT); System.out.println(path); client.close();
這個(gè)寫法中必須要注意的是 1 處的 username:password
的字符串必須通過 DigestAuthenticationProvider.generateDigest
的方法包裝一下,用這個(gè)方法會(huì)對(duì)傳入的字符串進(jìn)行編碼。
包裝完后 laoxun:kaixin
其實(shí)變成了 laoxun:/xQjqfEf7WHKtjj2csJh2/aEee8=
,這個(gè)過程如下:
laoxun:kaixin
對(duì)整個(gè)字符串先進(jìn)行 SHA1 加密
對(duì)加密后的結(jié)果進(jìn)行 Base64 編碼
將用戶名和編碼后的結(jié)果拼接
上面的代碼還有一種寫法如下,使用 addAuthInfo
在客戶端上下文中添加權(quán)限信息
ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null); client.addAuthInfo("digest", "laoxun:kaixin".getBytes()); // 1. List<acl> aclList = new ArrayList<>(); aclList.add(new ACL(ZooDefs.Perms.ALL, new Id("auth", ""))); // 2. 這里的 Id 是固定寫法 String path = client.create("/abc", "test".getBytes(), aclList, CreateMode.PERSISTENT); System.out.println(path); client.close();
這里有兩個(gè)改動(dòng),在 1 處使用 addAuthInfo
的方法可以在當(dāng)前客戶端的會(huì)話中添加 auth 信息,Digest 的 id 取值為 username:password
直接用明文即可,無論是 username 還是 password 都是自定義的。
然后是查詢代碼
ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null); client.addAuthInfo("digest", "laoxun:kaixin".getBytes()); // 這行如果注釋的話就會(huì)報(bào)錯(cuò) byte[] data = client.getData("/abc", false, null); System.out.println(new String(data)); // test
不管創(chuàng)建的時(shí)候是何種寫法,查詢的時(shí)候都要使用 addAuthInfo
在會(huì)話中添加權(quán)限信息,才能對(duì)該節(jié)點(diǎn)進(jìn)行查詢
聽名字就知道這個(gè)模式是管理員的模式了,因?yàn)橹皠?chuàng)建的那些節(jié)點(diǎn),如果設(shè)置了用戶名密碼,其他客戶端是無法訪問的,如果該客戶端自己退出了,這些節(jié)點(diǎn)就無法去操作了,所以需要管理員這一個(gè)角色來對(duì)其進(jìn)行降維打擊。
首先 Super 模式是要開啟的,我這里假設(shè)管理員的用戶名為 HelloZooKeeper,密碼為 niubi,經(jīng)過編碼后就是 HelloZooKeeper:PT8Sb6Exg9YyPCS7fYraLCsqzR8=
, 然后需要在服務(wù)端啟動(dòng)的環(huán)境中指定 zookeeper.DigestAuthenticationProvider.superDigest
配置,參數(shù)就是 HelloZooKeeper:PT8Sb6Exg9YyPCS7fYraLCsqzR8=
即可。
創(chuàng)建節(jié)點(diǎn)假設(shè)還是以 laoxun:kaixin
的模式,然后通過管理員的密碼也能進(jìn)行正常的訪問
ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null); client.addAuthInfo("digest", "HelloZooKeeper:niubi".getBytes()); // 1. byte[] data = client.getData("/abc", false, null); System.out.println(new String(data)); // test client.close();
這里可以看到 1 處的 Super 模式本質(zhì)上還是 Digest,指定的 scheme 為 digest,然后之后的 id 取值采用的是明文,而非編碼后的格式,切記!
我這里列出大部分服務(wù)端提供的操作對(duì)應(yīng)的 Permission 權(quán)限:
操作 | 所需權(quán)限 | 描述 |
---|---|---|
create | 父節(jié)點(diǎn)的 CREATE | 創(chuàng)建節(jié)點(diǎn) |
create2 | 父節(jié)點(diǎn)的 CREATE | 創(chuàng)建節(jié)點(diǎn),同時(shí)返回節(jié)點(diǎn)數(shù)據(jù) |
createContainer | 父節(jié)點(diǎn)的 CREATE | 創(chuàng)建容器節(jié)點(diǎn) |
createTTL | 父節(jié)點(diǎn)的 CREATE | 創(chuàng)建帶超時(shí)時(shí)間的節(jié)點(diǎn) |
delete | 父節(jié)點(diǎn)的 DELETE | 刪除節(jié)點(diǎn) |
setData | 當(dāng)前節(jié)點(diǎn)的 WRITE | 設(shè)置節(jié)點(diǎn)數(shù)據(jù) |
setACL | 當(dāng)前節(jié)點(diǎn)的 ADMIN | 設(shè)置節(jié)點(diǎn)的權(quán)限信息 |
reconfig | 當(dāng)前節(jié)點(diǎn)的 WRITE | 重新設(shè)置一些配置(之后有機(jī)會(huì)介紹) |
getData | 當(dāng)前節(jié)點(diǎn)的 READ | 查詢節(jié)點(diǎn)數(shù)據(jù) |
getChildren | 當(dāng)前節(jié)點(diǎn)的 READ | 獲取子節(jié)點(diǎn)列表 |
getChildren2 | 當(dāng)前節(jié)點(diǎn)的 READ | 獲取子節(jié)點(diǎn)列表 |
getAllChildrenNumber | 當(dāng)前節(jié)點(diǎn)的 READ | 獲取所有子節(jié)點(diǎn)(包含孫子節(jié)點(diǎn))數(shù)量 |
getACL | 當(dāng)前節(jié)點(diǎn)的 ADMIN 或 READ | 獲取節(jié)點(diǎn)的權(quán)限信息 |
可以看到刪除和創(chuàng)建節(jié)點(diǎn)看的是父節(jié)點(diǎn)的權(quán)限,只有讀寫才是看的自己本身的權(quán)限。另外如果表格中沒有出現(xiàn)的操作可以認(rèn)為不需要 ACL 權(quán)限校驗(yàn),其他要么是只需要客戶端是一個(gè)合法的 session 或者本身是一些比較特殊的功能,例如:createSession、closeSession 等。至于關(guān)于 session 的更多內(nèi)容,留到下一篇再講吧~哈哈
我們剛剛花了一點(diǎn)篇幅介紹了 ACL 是什么,怎么用?現(xiàn)在深入了解下 ACL 在 ZK 的服務(wù)端底層是怎么去實(shí)現(xiàn)的吧~為了節(jié)約篇幅,這次就直接進(jìn)入猿話講解了。
首先祭出之前的一張圖,喚醒下大家的記憶
圖中權(quán)限部分(藍(lán)色字體)之前的文章直接省略跳過了,沒有進(jìn)行解釋,今天我們就好好講講這個(gè)權(quán)限字段。
從圖上也能看到權(quán)限這個(gè)字段是直接以數(shù)字(long 類型,64 位的整型數(shù)字)的方式保存在服務(wù)端的節(jié)點(diǎn)中的,而 -1 是一個(gè)特殊的值代表不進(jìn)行權(quán)限的校驗(yàn)對(duì)應(yīng)的就是之前的 OPEN_ACL_UNSAFE
常量。
而 ACL 權(quán)限無論是創(chuàng)建節(jié)點(diǎn)時(shí)提供的(ACL 參數(shù)是一個(gè) List),還是通過 addAuth
方法提供的(這個(gè)方法可以被調(diào)用多次),這兩種設(shè)計(jì)都表示一個(gè)客戶端是可以擁有多種權(quán)限的,比如:多個(gè)用戶名密碼,多個(gè) IP 地址等等。
ACL 我之前講過是由 3 個(gè)部分組成的,即 scheme:id:perms
為了簡(jiǎn)潔的表示我會(huì)在之后使用該形式去表示一個(gè) ACL。
服務(wù)端會(huì)使用兩個(gè)哈希表把目前接收到的 ACL 列表和其對(duì)應(yīng)的數(shù)字雙向的關(guān)系保存起來,類似這樣(圖中的 ACL 取值是我隨意編造的):
ZK 服務(wù)端會(huì)維護(hù)一個(gè)從 1 開始的數(shù)字,收到一個(gè)新的 ACL 會(huì)同時(shí)放入這兩個(gè)哈希表(源碼中對(duì)應(yīng)的就是兩個(gè) Map
,一個(gè)是 Map<list<acl>, Long>
,一個(gè)是 Map<long, list<acl>>
),除了這兩個(gè)哈希表以外,ZK 服務(wù)端還為每一個(gè)客戶端都維護(hù)了一個(gè)會(huì)話中的權(quán)限信息,該權(quán)限信息就是客戶端通過 addAuth
添加的,但是這個(gè)客戶端的權(quán)限信息只保存了 scheme:id
部分,所以結(jié)合以下三個(gè)信息就可以對(duì)客戶端的本次操作進(jìn)行權(quán)限校驗(yàn)了:
兩個(gè)哈希表表示的節(jié)點(diǎn)的信息 scheme:id:perms
,可以有多個(gè)
客戶端會(huì)話上下文中的權(quán)限信息僅 id:perms
,可以有多個(gè)
本次操作對(duì)應(yīng)的權(quán)限要求,即 3.3 表格中列出的所需權(quán)限
校驗(yàn)的流程如下:
這里額外提一下,校驗(yàn)器是可以自定義的,用戶可以自定義自己的 scheme 以及自己的校驗(yàn)邏輯,需要在服務(wù)端的環(huán)境變量中配置以 zookeeper.authProvider.
開頭的配置,對(duì)應(yīng)的值則對(duì)應(yīng)一個(gè) class 類全路徑,這個(gè)類必須實(shí)現(xiàn) org.apache.zookeeper.server.auth.AuthenticationProvider
接口,而且這個(gè)類必須能被 ZK 服務(wù)端加載到,這樣就可以解析自定義的 scheme 控制整個(gè)校驗(yàn)邏輯了,這個(gè)功能比較高級(jí),我也沒用過,大家就當(dāng)補(bǔ)充知識(shí)了解下~
到此,相信大家對(duì)“ZooKeeper集群的數(shù)據(jù)同步過程是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
當(dāng)前文章:ZooKeeper集群的數(shù)據(jù)同步過程是什么
本文鏈接:http://aaarwkj.com/article6/pcohig.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、定制網(wǎng)站、服務(wù)器托管、搜索引擎優(yōu)化、網(wǎng)站營(yíng)銷、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)