溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

發(fā)布時(shí)間:2021-10-15 10:35:21 來(lái)源:億速云 閱讀:115 作者:iii 欄目:編程語(yǔ)言

本篇內(nèi)容主要講解“ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么”吧!

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

一、選舉完成

經(jīng)歷了選舉之后,我們的馬果果榮耀當(dāng)選當(dāng)前辦事處集群的 Leader,所以現(xiàn)在假設(shè)各個(gè)辦事處的關(guān)系圖是這樣:

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

我們現(xiàn)在就來(lái)說(shuō)說(shuō)馬小云馬小騰是如何同馬果果進(jìn)行數(shù)據(jù)同步的。

結(jié)束了累人的選舉后,馬小云馬小騰以微弱的優(yōu)勢(shì)輸?shù)袅烁?jìng)爭(zhēng),只能委屈成為 Follower。整理完各自的情緒后,他們要做的第一件事情就是通過(guò)話務(wù)員上報(bào)自己的信息給馬果果,使用了專門的暗號(hào) FOLLOWERINFO, 數(shù)據(jù)主要有自己的 epoch 和 myid:

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

然后是馬果果這邊,他收到 FOLLOWERINFO 之后也會(huì)進(jìn)行統(tǒng)計(jì),直到達(dá)到半數(shù)以上后,綜合各個(gè) Follower 給的信息會(huì)計(jì)算出新的 epoch,然后將這個(gè)新的 epoch 隨著暗號(hào) LEADERINFO 回發(fā)給其他 Follower

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

然后再回到馬小云馬小騰這邊,收到 LEADERINFO 之后將新的 epoch 記錄下來(lái),然后回復(fù)給馬果果一個(gè) ACKEPOCH 暗號(hào)并帶上自己這邊的最大 zxid,表示剛剛的 LEADERINFO 收到了

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

然后馬果果這邊也會(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)行判斷的,接下來(lái)一一進(jìn)行講解。

1.1 DIFF

每一個(gè) ZK 節(jié)點(diǎn)在收到寫請(qǐng)求后,會(huì)維護(hù)一個(gè)寫請(qǐng)求隊(duì)列(默認(rèn)是 500 大小,通過(guò) 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è)值之后,我們來(lái)看看 DIFF 是怎么判斷的。

1.1.1 從內(nèi)存中的寫請(qǐng)求隊(duì)列恢復(fù)

一種情況就是如果當(dāng) Follower 通過(guò) ACKEPOCH 上報(bào)的 zxid 是在 min 和 max 之間的話,就采用 DIFF 策略進(jìn)行數(shù)據(jù)同步。

我們的例子中 Leader 的 zxid 是 99,說(shuō)明這個(gè)存儲(chǔ) 500 個(gè)寫請(qǐng)求的隊(duì)列根本沒(méi)有放滿,所以 min 是 1 max 是 99,很顯然 77 以及 88 是在這個(gè)區(qū)間內(nèi)的,那馬果果就會(huì)為另外兩位 Follower 找到他們各自所需要的區(qū)間,先發(fā)送一個(gè) DIFF 給 Follower,然后將一條條的寫請(qǐng)求包裝成 PROPOSAL 和 COMMIT 的順序發(fā)給他們

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

1.1.2 從磁盤文件 log 恢復(fù)

另一種情況是如果 Follower 的 zxid 不在 min 和 max 的區(qū)間內(nèi)時(shí),但當(dāng) zookeeper.snapshotSizeFactor 配置大于 0 的話(默認(rèn)是 0.33),會(huì)嘗試使用 log 進(jìn)行 DIFF,但是需要同步的 log 文件的總大小不能超過(guò)當(dāng)前最新的 snapshot 文件大小的三分之一(以默認(rèn) 0.33 為例)的話,才可以通過(guò)讀取 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 是一致的。

1.2 SNAP

假設(shè)現(xiàn)在三個(gè)辦事處是這樣的

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

馬果果的寫請(qǐng)求隊(duì)列在默認(rèn)配置下記錄了 277 至 777 的寫請(qǐng)求,又假設(shè)現(xiàn)在的場(chǎng)景不滿足上面 1.1.2 的情況,馬果果就知道當(dāng)前需要通過(guò) SNAP 的情況進(jìn)行同步了。

馬果果會(huì)先發(fā)送一個(gè) SNAP 的請(qǐng)求給馬小云馬小騰讓他們準(zhǔn)備起來(lái)

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

緊接著就會(huì)當(dāng)前內(nèi)存中的數(shù)據(jù)整個(gè)序列化(和 snapshot 文件是一樣的)然后一起發(fā)送給馬小云馬小騰。

馬小云馬小騰收到馬果果發(fā)來(lái)的整個(gè) snapshot 之后會(huì)先清空自己當(dāng)前的數(shù)據(jù)庫(kù)的所有信息,接著直接將收到的 snapshot 反序列化就完成了整個(gè)內(nèi)存數(shù)據(jù)的恢復(fù)。

1.3 TRUNC

最后一種策略的場(chǎng)景假設(shè)是這樣:

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

假設(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 給馬小騰(這里忽略馬小云

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

假設(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 開(kāi)始,這樣就會(huì)把之后的那些記錄給覆蓋了。


馬果果這邊當(dāng)判斷完同步策略并發(fā)送給另外兩馬之后,便會(huì)發(fā)送一個(gè) NEWLEADER 的信息給他們

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

馬小云馬小騰在收到 NEWLEADER 之后,若之前是通過(guò) SNAP 方式同步數(shù)據(jù)的話,這里會(huì)強(qiáng)制快照一份新的 snapshot 文件在自己這里。然后會(huì)回復(fù)給馬果果一個(gè) ACK 的消息,告訴他自己的同步數(shù)據(jù)已經(jīng)完成了

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

然后馬果果同樣會(huì)等待半數(shù)一樣的 ACK 接收完成后,再發(fā)送一個(gè) UPTODATE 給其他兩馬,告訴他們現(xiàn)在辦事處數(shù)據(jù)已經(jīng)都一致了,可以開(kāi)始對(duì)外提供服務(wù)了

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

然后馬小云馬果果收到 UPTODATE 之后會(huì)再回復(fù)一個(gè) ACK 給馬果果,但是這次馬果果收到這次的 ACK 之后不會(huì)做處理,所以在 UPTODATE 之后,各個(gè)辦事處就已經(jīng)算可以正式對(duì)外提供服務(wù)了。


上面說(shuō)了這么多,但是馬小云馬小騰都是 Follower,如果是 Observer 呢?怎么用上面的步驟同步呢?

區(qū)別就在第一步,F(xiàn)ollower 發(fā)送的是 FOLLOWERINFO,而 Observer 發(fā)送的是 OBSERVERINFO 除此之外沒(méi)有任何區(qū)別,和 Follower 是一樣的步驟進(jìn)行數(shù)據(jù)同步。

二、繼續(xù)深挖

現(xiàn)在把其中的一些細(xì)節(jié)再用猿話說(shuō)明一下,三種不同的數(shù)據(jù)同步策略,Leader 在發(fā)送 Follower 的時(shí)候采用的具體方法是不太相同的

2.1 三種策略發(fā)送方式

如果采用的是 DIFF 或者 TRUNC 的同步方法的話,Leader 其實(shí)不是在找到有差異數(shù)據(jù)的時(shí)候發(fā)送過(guò)去的,而是按照順序先放入一個(gè)隊(duì)列,最后再統(tǒng)一啟動(dòng)一個(gè)線程去一個(gè)個(gè)發(fā)送的

DIFF :

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

TRUNC:

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

但是以 SNAP 方式同步的話就不會(huì)放入該隊(duì)列,無(wú)論是 SNAP 消息還是之后整個(gè)序列化后的內(nèi)存快照 snapshot 都會(huì)直接通過(guò)服務(wù)端間的 socket 直接寫入。

2.2 上帝視角

讓我們把三種策略消息交互的全過(guò)程再看一遍,這里就以馬小云舉例了

2.2.1 DIFF

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

2.2.2 TRUNC

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

2.2.3 SNAP

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么


可以看到首尾是一樣的,就是中間的請(qǐng)求根據(jù)不同的策略會(huì)有不同的請(qǐng)求發(fā)送。差不多到這里關(guān)于 Follower 或 Observer 是如何同 Leader 同步消息,整體的邏輯都介紹完了。

2.3 小結(jié)

  • 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)料,開(kāi)一個(gè)小篇講一下 ACL,這個(gè)我拖了很久沒(méi)解釋的坑。

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

三、沒(méi)有規(guī)矩,不成方圓

先帶大家重拾記憶,之前創(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)模式,下面我們一起來(lái)了解下。

3.1 權(quán)限 Permission 介紹

首先 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 就說(shuō)明擁有該權(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

3.2 Scheme 介紹

Scheme 有 4 種,分別是 ip、world、digestsuper,但是其實(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ù)端 “我是誰(shuí)?”,而最后的部分 perms 則是代表了 “我能做什么?”,這兩個(gè)問(wèn)題,任意一個(gè)問(wèn)題出錯(cuò)都會(huì)導(dǎo)致服務(wù)端拋出 NoAuthException 的異常,告訴客戶端權(quán)限不夠。

3.2.1 IP

我們先來(lái)直接看一段代碼,其中的 IP 10.11.12.13 我是隨便寫的

ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null);
List<acl> aclList = new ArrayList&lt;&gt;();
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 是可以被正確輸出的,而且通過(guò)查看 / 的子節(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)在如果去訪問(wè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),之后就能正常訪問(wèn)了,一般生產(chǎn)環(huán)境中 IP 模式用的不多(也可能是我用的不多),如果要用 IP 控制訪問(wèn)的話,通過(guò)防火墻白名單之類的手段即可,這個(gè)層面我認(rèn)為不需要 ZK 去管。

3.2.2 World

這個(gè)模式應(yīng)該是最常用的(手動(dòng)狗頭)

我們還是來(lái)看一段代碼

ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null);
List<acl> aclList = new ArrayList&lt;&gt;();
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)));
3.2.3 Digest

這個(gè)就是我們熟悉的用戶名密碼了,還是先上代碼

ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null);

List<acl> aclList = new ArrayList&lt;&gt;();
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 的字符串必須通過(guò) DigestAuthenticationProvider.generateDigest 的方法包裝一下,用這個(gè)方法會(huì)對(duì)傳入的字符串進(jìn)行編碼。

包裝完后 laoxun:kaixin 其實(shí)變成了 laoxun:/xQjqfEf7WHKtjj2csJh2/aEee8=,這個(gè)過(guò)程如下:

  • 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&lt;&gt;();
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 直接用明文即可,無(wú)論是 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)行查詢

3.2.4 Super

聽(tīng)名字就知道這個(gè)模式是管理員的模式了,因?yàn)橹皠?chuàng)建的那些節(jié)點(diǎn),如果設(shè)置了用戶名密碼,其他客戶端是無(wú)法訪問(wèn)的,如果該客戶端自己退出了,這些節(jié)點(diǎn)就無(wú)法去操作了,所以需要管理員這一個(gè)角色來(lái)對(duì)其進(jìn)行降維打擊。

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

首先 Super 模式是要開(kāi)啟的,我這里假設(shè)管理員的用戶名為 HelloZooKeeper,密碼為 niubi,經(jīng)過(guò)編碼后就是 HelloZooKeeper:PT8Sb6Exg9YyPCS7fYraLCsqzR8=, 然后需要在服務(wù)端啟動(dòng)的環(huán)境中指定 zookeeper.DigestAuthenticationProvider.superDigest 配置,參數(shù)就是 HelloZooKeeper:PT8Sb6Exg9YyPCS7fYraLCsqzR8= 即可。

創(chuàng)建節(jié)點(diǎn)假設(shè)還是以 laoxun:kaixin 的模式,然后通過(guò)管理員的密碼也能進(jìn)行正常的訪問(wè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 取值采用的是明文,而非編碼后的格式,切記!

3.3 Permission 匯總表格

我這里列出大部分服務(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)限。另外如果表格中沒(méi)有出現(xiàn)的操作可以認(rèn)為不需要 ACL 權(quán)限校驗(yàn),其他要么是只需要客戶端是一個(gè)合法的 session 或者本身是一些比較特殊的功能,例如:createSession、closeSession 等。至于關(guān)于 session 的更多內(nèi)容,留到下一篇再講吧~哈哈

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

3.4 ACL 背后的原理

我們剛剛花了一點(diǎn)篇幅介紹了 ACL 是什么,怎么用?現(xiàn)在深入了解下 ACL 在 ZK 的服務(wù)端底層是怎么去實(shí)現(xiàn)的吧~為了節(jié)約篇幅,這次就直接進(jìn)入猿話講解了。

首先祭出之前的一張圖,喚醒下大家的記憶

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

圖中權(quán)限部分(藍(lán)色字體)之前的文章直接省略跳過(guò)了,沒(méi)有進(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)限無(wú)論是創(chuàng)建節(jié)點(diǎn)時(shí)提供的(ACL 參數(shù)是一個(gè) List),還是通過(guò) addAuth 方法提供的(這個(gè)方法可以被調(diào)用多次),這兩種設(shè)計(jì)都表示一個(gè)客戶端是可以擁有多種權(quán)限的,比如:多個(gè)用戶名密碼,多個(gè) IP 地址等等。

ACL 我之前講過(guò)是由 3 個(gè)部分組成的,即 scheme:id:perms 為了簡(jiǎn)潔的表示我會(huì)在之后使用該形式去表示一個(gè) ACL。

服務(wù)端會(huì)使用兩個(gè)哈希表把目前接收到的 ACL 列表和其對(duì)應(yīng)的數(shù)字雙向的關(guān)系保存起來(lái),類似這樣(圖中的 ACL 取值是我隨意編造的):

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

ZK 服務(wù)端會(huì)維護(hù)一個(gè)從 1 開(kāi)始的數(shù)字,收到一個(gè)新的 ACL 會(huì)同時(shí)放入這兩個(gè)哈希表(源碼中對(duì)應(yīng)的就是兩個(gè) Map,一個(gè)是 Map<list<acl>, Long&gt;,一個(gè)是 Map<long, list<acl>&gt;),除了這兩個(gè)哈希表以外,ZK 服務(wù)端還為每一個(gè)客戶端都維護(hù)了一個(gè)會(huì)話中的權(quán)限信息,該權(quán)限信息就是客戶端通過(guò) 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)的流程如下:

ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么

這里額外提一下,校驗(yàn)器是可以自定義的,用戶可以自定義自己的 scheme 以及自己的校驗(yàn)邏輯,需要在服務(wù)端的環(huán)境變量中配置以 zookeeper.authProvider. 開(kāi)頭的配置,對(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í),我也沒(méi)用過(guò),大家就當(dāng)補(bǔ)充知識(shí)了解下~

到此,相信大家對(duì)“ZooKeeper集群的數(shù)據(jù)同步過(guò)程是什么”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI