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

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

創(chuàng)新互聯(lián)主營嘉蔭網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,成都App制作,嘉蔭h5微信平臺小程序開發(fā)搭建,嘉蔭網(wǎng)站營銷推廣歡迎嘉蔭等地區(qū)企業(yè)咨詢

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

一、選舉完成

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

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

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

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

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

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

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

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

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

然后馬果果這邊也會等待半數(shù)以上的 ACKEPOCH 的通知,收到之后會根據(jù)各個 Follower 的信息給出不同的同步策略。關(guān)于不同的同步策略,這里我先入為主的給大家介紹一下:

  • DIFF,如果 Follower 的記錄和 Leader 的記錄相差的不多,使用增量同步的方式將一個一個寫請求發(fā)送給 Follower

  • TRUNC,這個情況的出現(xiàn)代表 Follower 的 zxid 是領(lǐng)先于當(dāng)前的 Leader 的(可能是以前的 Leader),需要 Follower 自行把多余的部分給截斷,降級到和 Leader 一致

  • SNAP,如果 Follower 的記錄和當(dāng)前 Leader 相差太多,Leader 直接將自己的整個內(nèi)存數(shù)據(jù)發(fā)送給 Follower

至于采用哪一種策略,是如何進行判斷的,接下來一一進行講解。

1.1 DIFF

每一個 ZK 節(jié)點在收到寫請求后,會維護一個寫請求隊列(默認是 500 大小,通過 zookeeper.commitLogCount 配置),將寫請求記錄在其中,這個隊列中的最早進入的寫請求當(dāng)時的 zxid 就是 minZxid(以下簡稱 min),最后一個進入的寫請求的 zxid 就是 maxZxid(以下簡稱 max),達到上限后,會移除最早進入的寫請求,知道了這兩個值之后,我們來看看 DIFF 是怎么判斷的。

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

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

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

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

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

另一種情況是如果 Follower 的 zxid 不在 min 和 max 的區(qū)間內(nèi)時,但當(dāng) zookeeper.snapshotSizeFactor 配置大于 0 的話(默認是 0.33),會嘗試使用 log 進行 DIFF,但是需要同步的 log 文件的總大小不能超過當(dāng)前最新的 snapshot 文件大小的三分之一(以默認 0.33 為例)的話,才可以通過讀取 log 文件中的寫請求記錄進行 DIFF 同步。同步的方法也和上面一樣,先發(fā)送一個 DIFF 給 Follower 然后從 log 文件中找到該 Follower 的區(qū)間,再一條條的發(fā)送 PROPOSAL 和 COMMIT。

而 Follower 收到 PROPOSAL 的暗號消息后,就會像處理客戶端請求那樣去一條條處理,慢慢就會將數(shù)據(jù)恢復(fù)成和 Leader 是一致的。

1.2 SNAP

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

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

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

馬果果會先發(fā)送一個 SNAP 的請求給馬小云馬小騰讓他們準(zhǔn)備起來

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

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

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

1.3 TRUNC

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

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

假設(shè)馬小騰是上一個 Leader,但是經(jīng)歷了停電以后恢復(fù)重新以 Follower 的身份加入集群,但是他的 zxid 要比 max 還大,這個時候馬果果就會給馬小騰發(fā)送 TRUNC,(至于圖中為什么馬小云不舉例為 TRUNC,因為如果馬小云的 zxid 也比馬果果要大的話,馬果果在當(dāng)前場景下就不可能當(dāng)選 Leader 了)。

馬果果就會發(fā)送 TRUNC 給馬小騰(這里忽略馬小云

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

假設(shè)馬小騰的本地 log 文件目錄下是這樣的:

/tmp
└── zookeeper
    └── log
    		└── version-2
    				└── log.0
    				└── log.500
    				└── log.800

馬小騰收到 TRUNC 之后,會找到本地 log 文件中所有大于 777 的 log 文件刪除,即這里的 log.800 ,然后會在 log.500 這個文件找到 777 這個 zxid 記錄并且把當(dāng)前文件的讀寫指針修改至 777 的位置,之后針對該文件的讀寫操作就會從 777 開始,這樣就會把之后的那些記錄給覆蓋了。


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

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

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

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

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

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

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


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

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

二、繼續(xù)深挖

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

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

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

DIFF :

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

TRUNC:

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

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

2.2 上帝視角

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

2.2.1 DIFF

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

2.2.2 TRUNC

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

2.2.3 SNAP

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


可以看到首尾是一樣的,就是中間的請求根據(jù)不同的策略會有不同的請求發(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 還要大的時候,該節(jié)點需要主動刪除多余 zxid 相關(guān)的數(shù)據(jù),降級至 Leader 一致

  • SNAP 作為最后的數(shù)據(jù)同步手段,由 Leader 直接將內(nèi)存數(shù)據(jù)整個序列化完并發(fā)送給 Follower 或 Observer,以達到恢復(fù)數(shù)據(jù)的目的

我看了下文章的字數(shù)還行,決定加一點料,開一個小篇講一下 ACL,這個我拖了很久沒解釋的坑。

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

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

先帶大家重拾記憶,之前創(chuàng)建節(jié)點代碼片段中的 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é)點放棄 ACL 校驗,默認是 no

那這個 ACL 是怎么規(guī)定的,有哪些權(quán)限,又是怎么在服務(wù)端體現(xiàn)的呢?首先 ACL 整體分為 Permission 和 Scheme 兩部分,Permission 是針對操作的權(quán)限,而 Scheme 是指定使用哪一種鑒權(quán)模式,下面我們一起來了解下。

3.1 權(quán)限 Permission 介紹

首先 ZK 將權(quán)限分為 5 種:

  • READ(以下簡稱 R),獲取節(jié)點數(shù)據(jù)或者獲取子節(jié)點列表

  • WRITE(以下簡稱 W),設(shè)置節(jié)點數(shù)據(jù)

  • CREATE(以下簡稱 C),創(chuàng)建節(jié)點

  • DELETE(以下簡稱 D),刪除節(jié)點

  • ADMIN(以下簡稱 A),設(shè)置節(jié)點的 ACL 權(quán)限

然后該 5 種權(quán)限在代碼層面就是簡單的 int 數(shù)據(jù),而判斷是否有權(quán)限只需要用 & 操作即可,和目標(biāo)權(quán)限 & 完結(jié)果只要不等于 0 就說明擁有該權(quán)限,細節(jié)如下:

		int		binary
R		1			00001
W		2			00010
C		4			00100
D		8			01000
A		16		10000

假設(shè)現(xiàn)在的客戶端權(quán)限為 RWC,對應(yīng)的數(shù)值就是各個權(quán)限相加 1 + 2 + 4 = 7

		int		binary
RWC	7			00111

對任意有 R、W、C 權(quán)限需求的節(jié)點,求 & 的結(jié)果都不為 0,所以就能判斷該客戶端是擁有 RWC 這 3 個權(quán)限的。

但是如果當(dāng)該客戶端對目標(biāo)節(jié)點進行刪除時,做 & 判斷權(quán)限的話,可以得到結(jié)果為 0,表示該客戶端不具備刪除的權(quán)限,就會返回給客戶端權(quán)限錯誤

		int		binary
RWC	7			00111
D		8		& 01000
------------------
結(jié)果 0		 00000

3.2 Scheme 介紹

Scheme 有 4 種,分別是 ipworld、digestsuper,但是其實就是兩大類,一種是針對 IP 地址的 ip,另一種是使用類似“用戶名:密碼”的 world、digest、super。其實整個 ACL 是分三個部分的,scheme:id:perms ,id 的取值取決于 scheme 的種類,這里是 ip 所以 id 的取值就是具體的 IP 地址,而 perms 則是我上一小節(jié)介紹的 RWCDA。

這三部分的前兩部分 scheme:id 相當(dāng)于告訴服務(wù)端 “我是誰?”,而最后的部分 perms 則是代表了 “我能做什么?”,這兩個問題,任意一個問題出錯都會導(dǎo)致服務(wù)端拋出 NoAuthException 的異常,告訴客戶端權(quán)限不夠。

3.2.1 IP

我們先來直接看一段代碼,其中的 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 是可以被正確輸出的,而且通過查看 / 的子節(jié)點列表是可以看到 /abc 節(jié)點的

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é)點的數(shù)據(jù)的話就會得到報錯

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é)點,之后就能正常訪問了,一般生產(chǎn)環(huán)境中 IP 模式用的不多(也可能是我用的不多),如果要用 IP 控制訪問的話,通過防火墻白名單之類的手段即可,這個層面我認為不需要 ZK 去管。

3.2.2 World

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

我們還是來看一段代碼

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,所以這個節(jié)點只能讀數(shù)據(jù),但不能做其他操作,如果使用 setData 對其進行數(shù)據(jù)修改的話也會得到權(quán)限的錯誤

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,其實就是 ZK 提供的常用的靜態(tài)常量,代表不校驗權(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

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

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();

這個寫法中必須要注意的是 1 處的 username:password 的字符串必須通過 DigestAuthenticationProvider.generateDigest 的方法包裝一下,用這個方法會對傳入的字符串進行編碼。

包裝完后 laoxun:kaixin 其實變成了 laoxun:/xQjqfEf7WHKtjj2csJh2/aEee8=,這個過程如下:

  • laoxun:kaixin 對整個字符串先進行 SHA1 加密

  • 對加密后的結(jié)果進行 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();

這里有兩個改動,在 1 處使用 addAuthInfo 的方法可以在當(dāng)前客戶端的會話中添加 auth 信息,Digest 的 id 取值為 username:password 直接用明文即可,無論是 username 還是 password 都是自定義的。

然后是查詢代碼

ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 3000, null);
client.addAuthInfo("digest", "laoxun:kaixin".getBytes()); // 這行如果注釋的話就會報錯
byte[] data = client.getData("/abc", false, null);
System.out.println(new String(data)); // test

不管創(chuàng)建的時候是何種寫法,查詢的時候都要使用 addAuthInfo 在會話中添加權(quán)限信息,才能對該節(jié)點進行查詢

3.2.4 Super

聽名字就知道這個模式是管理員的模式了,因為之前創(chuàng)建的那些節(jié)點,如果設(shè)置了用戶名密碼,其他客戶端是無法訪問的,如果該客戶端自己退出了,這些節(jié)點就無法去操作了,所以需要管理員這一個角色來對其進行降維打擊。

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

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

創(chuàng)建節(jié)點假設(shè)還是以 laoxun:kaixin 的模式,然后通過管理員的密碼也能進行正常的訪問

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ù)端提供的操作對應(yīng)的 Permission 權(quán)限:

操作所需權(quán)限描述
create父節(jié)點的 CREATE創(chuàng)建節(jié)點
create2父節(jié)點的 CREATE創(chuàng)建節(jié)點,同時返回節(jié)點數(shù)據(jù)
createContainer父節(jié)點的 CREATE創(chuàng)建容器節(jié)點
createTTL父節(jié)點的 CREATE創(chuàng)建帶超時時間的節(jié)點
delete父節(jié)點的 DELETE刪除節(jié)點
setData當(dāng)前節(jié)點的 WRITE設(shè)置節(jié)點數(shù)據(jù)
setACL當(dāng)前節(jié)點的 ADMIN設(shè)置節(jié)點的權(quán)限信息
reconfig當(dāng)前節(jié)點的 WRITE重新設(shè)置一些配置(之后有機會介紹)
getData當(dāng)前節(jié)點的 READ查詢節(jié)點數(shù)據(jù)
getChildren當(dāng)前節(jié)點的 READ獲取子節(jié)點列表
getChildren2當(dāng)前節(jié)點的 READ獲取子節(jié)點列表
getAllChildrenNumber當(dāng)前節(jié)點的 READ獲取所有子節(jié)點(包含孫子節(jié)點)數(shù)量
getACL當(dāng)前節(jié)點的 ADMIN 或 READ獲取節(jié)點的權(quán)限信息

可以看到刪除和創(chuàng)建節(jié)點看的是父節(jié)點的權(quán)限,只有讀寫才是看的自己本身的權(quán)限。另外如果表格中沒有出現(xiàn)的操作可以認為不需要 ACL 權(quán)限校驗,其他要么是只需要客戶端是一個合法的 session 或者本身是一些比較特殊的功能,例如:createSession、closeSession 等。至于關(guān)于 session 的更多內(nèi)容,留到下一篇再講吧~哈哈

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

3.4 ACL 背后的原理

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

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

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

圖中權(quán)限部分(藍色字體)之前的文章直接省略跳過了,沒有進行解釋,今天我們就好好講講這個權(quán)限字段。

從圖上也能看到權(quán)限這個字段是直接以數(shù)字(long 類型,64 位的整型數(shù)字)的方式保存在服務(wù)端的節(jié)點中的,而 -1 是一個特殊的值代表不進行權(quán)限的校驗對應(yīng)的就是之前的 OPEN_ACL_UNSAFE 常量。

而 ACL 權(quán)限無論是創(chuàng)建節(jié)點時提供的(ACL 參數(shù)是一個 List),還是通過 addAuth 方法提供的(這個方法可以被調(diào)用多次),這兩種設(shè)計都表示一個客戶端是可以擁有多種權(quán)限的,比如:多個用戶名密碼,多個 IP 地址等等。

ACL 我之前講過是由 3 個部分組成的,即 scheme:id:perms 為了簡潔的表示我會在之后使用該形式去表示一個 ACL。

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

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

ZK 服務(wù)端會維護一個從 1 開始的數(shù)字,收到一個新的 ACL 會同時放入這兩個哈希表(源碼中對應(yīng)的就是兩個 Map,一個是 Map<list<acl>, Long&gt;,一個是 Map<long, list<acl>&gt;),除了這兩個哈希表以外,ZK 服務(wù)端還為每一個客戶端都維護了一個會話中的權(quán)限信息,該權(quán)限信息就是客戶端通過 addAuth 添加的,但是這個客戶端的權(quán)限信息只保存了 scheme:id 部分,所以結(jié)合以下三個信息就可以對客戶端的本次操作進行權(quán)限校驗了:

  • 兩個哈希表表示的節(jié)點的信息 scheme:id:perms,可以有多個

  • 客戶端會話上下文中的權(quán)限信息僅 id:perms ,可以有多個

  • 本次操作對應(yīng)的權(quán)限要求,即 3.3 表格中列出的所需權(quán)限

校驗的流程如下:

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

這里額外提一下,校驗器是可以自定義的,用戶可以自定義自己的 scheme 以及自己的校驗邏輯,需要在服務(wù)端的環(huán)境變量中配置以 zookeeper.authProvider. 開頭的配置,對應(yīng)的值則對應(yīng)一個 class 類全路徑,這個類必須實現(xiàn) org.apache.zookeeper.server.auth.AuthenticationProvider 接口,而且這個類必須能被 ZK 服務(wù)端加載到,這樣就可以解析自定義的 scheme 控制整個校驗邏輯了,這個功能比較高級,我也沒用過,大家就當(dāng)補充知識了解下~

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

當(dāng)前文章:ZooKeeper集群的數(shù)據(jù)同步過程是什么
本文鏈接:http://bm7419.com/article6/pcohig.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動網(wǎng)站建設(shè)、定制網(wǎng)站、服務(wù)器托管搜索引擎優(yōu)化、網(wǎng)站營銷、外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)