ZooKeeper學習第一期---Zookeeper簡單介紹
ZooKeeper學習第二期--ZooKeeper安裝配置
ZooKeeper學習第三期---Zookeeper命令操作
ZooKeeper學習第四期---構建ZooKeeper應用
ZooKeeper學習第五期--ZooKeeper管理分布式環境中的數據
ZooKeeper學習第六期---ZooKeeper機制架構
ZooKeeper學習第七期--ZooKeeper一致性原理
ZooKeeper學習第八期——ZooKeeper伸縮性
一、ZooKeeper權限管理機制
1.1 權限管理ACL(Access Control List)
ZooKeeper 的權限管理亦即ACL 控制功能,使用ACL來對Znode進行訪問控制。ACL的實現和Unix文件訪問許可非常相似:它使用許可位來對一個節點的不同操作進行允許或禁止的權 限控制。但是和標准的Unix許可不同的是,Zookeeper對於用戶類別的區分,不止局限於所有者(owner)、組 (group)、所有人(world)三個級別。Zookeeper中,數據節點沒有"所有者"的概念。訪問者利用id標識自己的身份,並獲得與之相應的 不同的訪問權限。
ZooKeeper 的權限管理通過Server、Client 兩端協調完成:
(1) Server端
一個ZooKeeper 的節點存儲兩部分內容:數據和狀態,狀態中包含ACL 信息。創建一個znode 會產生一個ACL 列表,列表中每個ACL 包括:
① 權限perms
② 驗證模式scheme
③ 具體內容expression:Ids
例如,當scheme="digest" 時, Ids 為用戶名密碼, 即"root :J0sTy9BCUKubtK1y8pkbL7qoxSw"。ZooKeeper 提供了如下幾種驗證模式:
① Digest: Client 端由用戶名和密碼驗證,譬如user:pwd
② Host: Client 端由主機名驗證,譬如localhost
③ Ip:Client 端由IP 地址驗證,譬如172.2.0.0/24
④ World :固定用戶為anyone,為所有Client 端開放權限
當會話建立的時候,客戶端將會進行自我驗證。
權限許可集合如下:
① Create 允許對子節點Create 操作
② Read 允許對本節點GetChildren 和GetData 操作
③ Write 允許對本節點SetData 操作
④ Delete 允許對子節點Delete 操作
⑤ Admin 允許對本節點setAcl 操作
另外,ZooKeeper Java API支持三種標准的用戶權限,它們分別為:
① ZOO_PEN_ACL_UNSAFE:對於所有的ACL來說都是完全開放的,任何應用程序可以在節點上執行任何操作,比如創建、列出並刪除子節點。
② ZOO_READ_ACL_UNSAFE:對於任意的應用程序來說,僅僅具有讀權限。
③ ZOO_CREATOR_ALL_ACL:授予節點創建者所有權限。需要注意的是,設置此權限之前,創建者必須已經通了服務器的認證。
Znode ACL 權限用一個int 型數字perms 表示,perms 的5 個二進制位分別表示setacl、delete、create、write、read。比如adcwr=0x1f,----r=0x1,a-c-r=0x15。
注意的是,exists操作和getAcl操作並不受ACL許可控制,因此任何客戶端可以查詢節點的狀態和節點的ACL。
(2) 客戶端
Client 通過調用addAuthInfo()函數設置當前會話的Author信息(針對Digest 驗證模式)。Server 收到Client 發送的操作請求(除exists、getAcl 之外),需要進行ACL 驗證:對該請求攜帶的Author 明文信息加密,並與目標節點的ACL 信息進行比較,如果匹配則具有相應的權限,否則請求被Server 拒絕。
下面演示一個通過digest(用戶名:密碼的方式)為創建的節點設置ACL的例子,代碼如下:
package acl; import java.util.*; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Id; import org.apache.zookeeper.server.auth.DigestAuthenticationProvider; public class NewDigest { private static final String HOST1="192.168.56.90:2181"; private static final String HOST2="192.168.56.90:2182,192.168.56.90:2183,192.168.56.90:2184"; public static void main(String[] args) throws Exception {//new一個acl List<ACL> acls = new ArrayList<ACL>(); //添加第一個id,采用用戶名密碼形式 Id id1 = new Id("digest",DigestAuthenticationProvider.generateDigest("admin:admin")); ACL acl1 = new ACL(ZooDefs.Perms.ALL, id1); acls.add(acl1); //添加第二個id,所有用戶可讀權限 Id id2 = new Id("world", "anyone"); ACL acl2 = new ACL(ZooDefs.Perms.READ, id2); acls.add(acl2); // Zk用admin認證,創建/test ZNode。 ZooKeeper Zk = new ZooKeeper(HOST2,2000, null); Zk.addAuthInfo("digest", "admin:admin".getBytes()); Zk.create("/test", "data".getBytes(), acls, CreateMode.PERSISTENT); } }
1.2 ZooKeeper SuperDigest
(1) 一次Client 對Znode 進行操作的驗證ACL 的方式為:
a) 遍歷znode的所有ACL:
① 對於每一個ACL,首先操作類型與權限(perms)匹配
② 只有匹配權限成功才進行session 的auth 信息與ACL 的用戶名、密碼匹配
b) 如果兩次匹配都成功,則允許操作;否則,返回權限不夠error(rc=-102)
(2) 如果Znode ACL List 中任何一個ACL 都沒有setAcl 權限,那么就算superDigest 也修改不了它的權限;再假如這個Znode 還不開放delete 權限,那么它的所有子節點都將不會被刪除。唯一的辦法是通過手動刪除snapshot 和log 的方法,將ZK 回滾到一個以前的狀態,然后重啟,當然這會影響到該znode 以外其它節點的正常應用。
(3) superDigest 設置的步驟:
① 啟動ZK 的時候( zkServer.sh ) , 加入參數: Java"-Dzookeeper .DigestAuthenticationProvider.superDigest=super:D/InIHSb7yEEbrWz8b9l71RjZJU=" (無空格)。
② 在客戶端使用的時候, addAuthInfo("digest", "super:test", 10, 0, 0); " super:test" 為"super:D/InIHSb7yEEbrWz8b9l71RjZJU="的明文表示,加密算法同setAcl。
二、 Watch機制
Zookeeper客戶端在數據節點上設置監視,則當數據節點發生變化時,客戶端會收到提醒。ZooKeeper中的各種讀請求,如getDate(),getChildren(),和exists(),都可以選擇加"監視點"(watch)。"監視點"指的是一種一次性的觸發器(trigger),當受監視的數據發生變化時,該觸發器會通知客戶端。
(1) 監視機制有三個關鍵點:
① "監視點"是一次性的,當觸發過一次之后,除非重新設置,新的數據變化不會提醒客戶端。
② "監視點"將數據改變的通知客戶端。如果數據改變是客戶端A引起的,不能保證"監視點"通知事件會在引發數據修改的函數返回前到達客戶端A。
③ 對於"監視點",ZooKeeper有如下保證:客戶端一定是在接收到"監視"事件(watch event)之后才接收到數據的改變信息。
(2) "監視點"保留在ZooKeeper服務器上,則當客戶端連接到新的ZooKeeper服務器上時,所有需要被觸發的相關"監視點"都會被觸發。當客戶端斷線后重連,與它的相關的"監視點"都會自動重新注冊,這對客戶端來說是透明的。在以下情況,"監視點"會被錯過:客戶端B設置了關於節點A存在性的"監視點",但B斷線了,在B斷線過程中節點A被創建又被刪除。此時,B再連線后不知道A節點曾經被創建過。
(3) ZooKeeper的"監視"機制保證以下幾點:
① "監視"事件的觸發順序和事件的分發順序一致。
② 客戶端將先接收到"監視"事件,然后才收到新的數據
③ "監視"事件觸發的順序與ZooKeeper服務器上數據變化的順序一致
(4) 關於ZooKeeper"監視"機制的注意點:
① "監視點"是一次性的。
② 由於"監視點"是一次性的,而且,從接收到"監視"事件到設置新"監視點"是有延時的,所以客戶端可能監控不到數據的所有變化。
③ 一個監控對象,只會被相關的通知觸發一次。如果一個客戶端設置了關於某個數據點exists和getData的監控,則當該數據被刪除的時候,只會觸發"文件被刪除"的
通知。
④ 當客戶端斷開與服務器的連接時,客戶端不再能收到"監視"事件,直到重新獲得連接。所以關於Session的信息將被發送給所有ZooKeeper服務器。由於當連接斷開時收不到"監視",所以在這種情況下,模塊行為需要容錯方面的設計。
三、Session機制
3.1 會話概述
每個ZooKeeper客戶端的配置中都包括集合體中服務器的列表。在啟動時,客戶端會嘗試連接到列表中的一台服務器。如果連接失敗,它會嘗試連接另一台服務器,以此類推,直到成功與一台服務器建立連接或因為所有ZooKeeper服務器都不可用而失敗。
一旦客戶端與一台ZooKeeper服務器建立連接,這台服務器就會為該客戶端創建一個新的會話。每個會話都會有一個超時的時間設置,這個設置由創建會話的應用來設定。如果服務器在超時時間段內沒有收到任何請求,則相應的會話會過期。一旦一個會話已經過期,就無法重新打開,並且任何與該會話相關聯的短暫znode都會丟失。會話通常長期存在,而且會話過期是一種比較罕見的事件,但對應用來說,如何處理會話過期仍是非常重要的。
只要一個會話空閑超過一定時間,都可以通過客戶端發送ping請求(也稱為心跳)保持會話不過期。ping請求由ZooKeeper的客戶端庫自動發送,因此在我們的代碼中不需要考慮如何維護會話。這個時間長度的設置應當足夠低,以便能檔檢測出服務器故障(由讀超時體現),並且能夠在會話超時的時間段內重新蓮接到另外一台服務器。
3.2 故障切換
ZooKeeper客戶端可以自動地進行故障切換,切換至另一台ZooKeeper服務器。並且關鍵的一點是,在另一台服務器接替故障服務器之后,所有的會話和相關的短暫Znode仍然是有效的。在故障切換過程中,應用程序將收到斷開連接和連接至服務的通知。當客戶端斷開連接時,觀察通知將無法發送;但是當客戶端成功恢復連接后,這些延遲的通知會被發送。當然,在客戶端重新連接至另一台服務器的過程中,如果應用程序試圖執行一個操作,這個操作將會失敗。這充分體現了在真實的ZooKeeper應用中處理連接丟失異常的重要性。
四、ZooKeeper實例狀態
(1) ZooKeeper狀態
ZooKeeper對象在其生命周期中會經歷幾種不同的狀態。你可以在任何時刻通過getState()方法來查詢對象的狀態:
public States getState()
States被定義成代表ZooKeeper對象不同狀態的枚舉類型值(不管是什么枚舉值,一個ZooKeeper的實例在一個時刻只能處於一種狀態)。在試圖與ZooKeeper服務建立連接的過程中,一個新建的ZooKeeper實例處於CONNECTING狀態。一旦建立連接,它就會進入CONNECTED狀態。
通過注冊觀察對象,使用了ZooKeeper對象的客戶端可以收到狀態轉換通知。在進入CONNECTED狀態時,觀察對象會收到一個WatchedEvent通知,其中KeeperState的值是SyncConnected。
(2) Watch與ZooKeeper狀態
ZooKeeper的觀察對象肩負着雙重責任:
① 可以用來獲得ZooKeeper狀態變化的相關通知;
② 可以用來獲得Znode變化的相關通知。
監視ZooKeeper狀態變化:可以使用ZooKeeper對象默認構造函數的觀察。
監視Znode變化:可以使用一個專用的觀察對象,將其傳遞給適當的讀操作。也可以通過讀操作中的布爾標識來設定是否共享使用默認的觀察。
ZooKeeper實例可能失去或重新連接ZooKeeper服務,在CONNECTED和CONNECTING狀態中切換。如果連接斷 開,watcher得到一個Disconnected事件。學要注意的是,這些狀態的遷移是由ZooKeeper實例自己發起的,如果連接斷開他將自動嘗 試自動連接。
如果任何一個close()方法被調用,或是會話由Expired類型的KeepState提示過期時,ZooKeeper可能會轉變成第三種狀態 CLOSED。一旦處於CLOSED狀態,ZooKeeper對象將不再是活動的了(可以使用states的isActive()方法進行測試),而且不 能被重用。客戶端必須建立一個新的ZooKeeper實例才能重新連接到ZooKeeper服務。