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的例子,代碼如下:

    import org.apache.Zookeeper.*;
    import org.apache.Zookeeper.server.auth.DigestAuthenticationProvider;
    import org.apache.Zookeeper.data.*;
    import java.util.*;
    public class NewDigest {
        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("host1:2181,host2:2181,host3:2181",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服務器都不可用而失敗。

圖 3.1 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狀態。 

圖 3.2 ZooKeeper狀態轉換

通過注冊觀察對象,使用了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服務。

如果,您認為閱讀這篇博客讓您有些收獲,不妨點擊一下右下角的【推薦】。
如果,您希望更容易地發現我的新博客,不妨點擊一下左下角的【關注我】。
如果,您對我的博客所講述的內容有興趣,請繼續關注我的后續博客,我是【Sunddenly】。

本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM