1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        ZooKeeper核心知識總結(jié)!

        共 23909字,需瀏覽 48分鐘

         ·

        2022-04-20 21:46

        之前分享過幾個系列:

        今天這篇介紹一下ZooKeeper!

        「文章較長,可以點贊,收藏再看!」

        文章內(nèi)容會同步到個人網(wǎng)站上,方便閱讀:https://xiaoflyfish.cn/,(「可以訪問了!」

        782e1bf2667eb0f8ead3ec46023ab309.webp基本介紹

        Apache ZooKeeper 是由Apache Hadoop的子項目發(fā)展而來,為分布式應(yīng)用提供高效且可靠的分布式協(xié)調(diào)服務(wù)。

        • 在解決分布式數(shù)據(jù)一致性方面,ZK沒有直接采用Paxos算法,而是采用了ZAB(ZooKeeper Atomic Broadcast)協(xié)議。

        ZK可以提供諸如數(shù)據(jù)發(fā)布/訂閱、負載均衡、命名服務(wù)、分布式協(xié)調(diào)/通知,集群管理,Master選舉,分布式鎖,分布式隊列等功能。

        「它具有以下特性:」

        • 「順序一致性」:從一個客戶端發(fā)起的事務(wù)請求,最終都會嚴格按照其發(fā)起順序被應(yīng)用到 Zookeeper 中;
        • 「原子性」:要么所有應(yīng)用,要么不應(yīng)用;不存在部分機器應(yīng)用了該事務(wù),而「另一部分沒有應(yīng)用」的情況;
        • 「單一視圖」:所有客戶端看到的服務(wù)端數(shù)據(jù)模型都是一致的,無論客戶連接的是哪個ZK服務(wù)器;
        • 「可靠性」:一旦服務(wù)端成功應(yīng)用了一個事務(wù),則其引起的改變會一直保留,直到被另外一個事務(wù)所更改;
        • 「實時性」:一旦一個事務(wù)被成功應(yīng)用后,Zookeeper 可以保證客戶端立即可以讀取到這個事務(wù)變更后的最新狀態(tài)的數(shù)據(jù)(「一段時間」)。
        數(shù)據(jù)模型

        ZooKeeper 中的數(shù)據(jù)模型是一種樹形結(jié)構(gòu),非常像電腦中的文件系統(tǒng),有一個根文件夾,下面還有很多子文件夾。

        • ZooKeeper的數(shù)據(jù)模型也具有一個固定的根節(jié)點(/),我們可以在根節(jié)點下創(chuàng)建子節(jié)點,并在子節(jié)點下繼續(xù)創(chuàng)建下一級節(jié)點。

        • ZooKeeper 樹中的每一層級用斜杠(/)分隔開,且只能用絕對路徑(如get /work/task)的方式查詢 ZooKeeper 節(jié)點,而不能使用相對路徑。

        6e2d400327bb3a4f68d496b9d5b82cfa.webp

        「為什么 ZooKeeper 不能采用相對路徑查找節(jié)點呢?」

        ?

        這是因為 ZooKeeper 大多是應(yīng)用場景是定位數(shù)據(jù)模型上的節(jié)點,并在相關(guān)節(jié)點上進行操作。

        ?

        像這種查找與給定值相等的記錄問題最適合用散列來解決。

        因此 ZooKeeper 在底層實現(xiàn)的時候,使用了一個 hashtable,即 hashtableConcurrentHashMap nodes,用節(jié)點的完整路徑來作為 key 存儲節(jié)點數(shù)據(jù)。

        這樣就大大提高了 ZooKeeper 的性能。

        「節(jié)點類型」

        ZooKeeper 中的數(shù)據(jù)節(jié)點也分為持久節(jié)點、臨時節(jié)點和有序節(jié)點三種類型:

        ?

        1、持久節(jié)點

        ?

        一旦將節(jié)點創(chuàng)建為持久節(jié)點,該數(shù)據(jù)節(jié)點會一直存儲在 ZooKeeper 服務(wù)器上,即使創(chuàng)建該節(jié)點的客戶端與服務(wù)端的會話關(guān)閉了,該節(jié)點依然不會被刪除。如果我們想刪除持久節(jié)點,就要顯式調(diào)用 delete 函數(shù)進行刪除操作。

        ?

        2、臨時節(jié)點

        ?

        如果將節(jié)點創(chuàng)建為臨時節(jié)點,那么該節(jié)點數(shù)據(jù)不會一直存儲在 ZooKeeper 服務(wù)器上。

        當創(chuàng)建該臨時節(jié)點的客戶端會話因超時或發(fā)生異常而關(guān)閉時,該節(jié)點也相應(yīng)在 ZooKeeper 服務(wù)器上被刪除,同樣,我們可以像刪除持久節(jié)點一樣主動刪除臨時節(jié)點。

        在平時的開發(fā)中,我們可以利用臨時節(jié)點的這一特性來做服務(wù)器集群內(nèi)機器運行情況的統(tǒng)計,將集群設(shè)置為/servers節(jié)點,并為集群下的每臺服務(wù)器創(chuàng)建一個臨時節(jié)點/servers/host,當服務(wù)器下線時該節(jié)點自動被刪除,最后統(tǒng)計臨時節(jié)點個數(shù)就可以知道集群中的運行情況。

        ?

        3、有序節(jié)點

        ?

        節(jié)點有序是說在我們創(chuàng)建有序節(jié)點的時候,ZooKeeper 服務(wù)器會自動使用一個單調(diào)遞增的數(shù)字作為后綴,追加到我們創(chuàng)建節(jié)點的后邊。

        例如一個客戶端創(chuàng)建了一個路徑為 works/task-的有序節(jié)點,那么 ZooKeeper 將會生成一個序號并追加到該節(jié)點的路徑后,最后該節(jié)點的路徑為works/task-1。

        • 通過這種方式我們可以直觀的查看到節(jié)點的創(chuàng)建順序。

        ZooKeeper 中的每個節(jié)點都維護有這些內(nèi)容:一個二進制數(shù)組(byte data[]),用來存儲節(jié)點的數(shù)據(jù)、ACL 訪問控制信息、子節(jié)點數(shù)據(jù)(因為臨時節(jié)點不允許有子節(jié)點,所以其子節(jié)點字段為 null),除此之外每個數(shù)據(jù)節(jié)點還有一個記錄自身狀態(tài)信息的字段 stat。

        「節(jié)點的狀態(tài)結(jié)構(gòu)」

        執(zhí)行stat /zk_test,可以看到控制臺輸出了一些信息,這些就是節(jié)點狀態(tài)信息。

        每一個節(jié)點都有一個自己的狀態(tài)屬性,記錄了節(jié)點本身的一些信息:

        「狀態(tài)屬性」「說明」
        czxid數(shù)據(jù)節(jié)點創(chuàng)建時的事務(wù) ID
        ctime數(shù)據(jù)節(jié)點創(chuàng)建時的時間
        mzxid數(shù)據(jù)節(jié)點最后一次更新時的事務(wù) ID
        mtime數(shù)據(jù)節(jié)點最后一次更新時的時間
        pzxid數(shù)據(jù)節(jié)點的子節(jié)點最后一次被修改時的事務(wù) ID
        「cversion」「子節(jié)點的版本」
        「version」「當前節(jié)點數(shù)據(jù)的版本」
        「aversion」「節(jié)點的 ACL 的版本」
        ephemeralOwner如果節(jié)點是臨時節(jié)點,則表示創(chuàng)建該節(jié)點的會話的 SessionID;如果節(jié)點是持久節(jié)點,則該屬性值為 0
        dataLength數(shù)據(jù)內(nèi)容的長度
        numChildren數(shù)據(jù)節(jié)點當前的子節(jié)點個數(shù)

        「數(shù)據(jù)節(jié)點的版本」

        在 ZooKeeper 中為數(shù)據(jù)節(jié)點引入了版本的概念,每個數(shù)據(jù)節(jié)點有 3 種類型的版本信息,對數(shù)據(jù)節(jié)點的任何更新操作都會引起版本號的變化。

        ZooKeeper 的版本信息表示的是對節(jié)點數(shù)據(jù)內(nèi)容、子節(jié)點信息或者是 ACL 信息的修改次數(shù)。

        數(shù)據(jù)存儲

        從存儲位置上來說,事務(wù)日志和數(shù)據(jù)快照一樣,都存儲在本地磁盤上;而從業(yè)務(wù)角度來講,內(nèi)存數(shù)據(jù)就是我們創(chuàng)建數(shù)據(jù)節(jié)點、添加監(jiān)控等請求時直接操作的數(shù)據(jù)。

        • 事務(wù)日志數(shù)據(jù)主要用于記錄本地事務(wù)性會話操作,用于 ZooKeeper 集群服務(wù)器之間的數(shù)據(jù)同步。

        • 事務(wù)快照則是將內(nèi)存數(shù)據(jù)持久化到本地磁盤。

        ?

        這里要注意的一點是,數(shù)據(jù)快照是每間隔一段時間才把內(nèi)存數(shù)據(jù)存儲到本地磁盤,因此數(shù)據(jù)并不會一直與內(nèi)存數(shù)據(jù)保持一致。

        ?

        在單臺 ZooKeeper 服務(wù)器運行過程中因為異常而關(guān)閉時,可能會出現(xiàn)數(shù)據(jù)丟失等情況。

        「內(nèi)存數(shù)據(jù)」

        ZooKeeper 的數(shù)據(jù)模型可以看作一棵樹形結(jié)構(gòu),而數(shù)據(jù)節(jié)點就是這棵樹上的葉子節(jié)點。

        從數(shù)據(jù)存儲的角度看,ZooKeeper 的數(shù)據(jù)模型是存儲在內(nèi)存中的。

        我們可以把 ZooKeeper 的數(shù)據(jù)模型看作是存儲在內(nèi)存中的數(shù)據(jù)庫,而這個數(shù)據(jù)庫不但存儲數(shù)據(jù)的節(jié)點信息,還存儲每個數(shù)據(jù)節(jié)點的 ACL 權(quán)限信息以及 stat 狀態(tài)信息等。

        • 而在底層實現(xiàn)中,ZooKeeper 數(shù)據(jù)模型是通過 DataTree 類來定義的。

        DataTree 類定義了一個 ZooKeeper 數(shù)據(jù)的內(nèi)存結(jié)構(gòu)。

        DataTree 的內(nèi)部定義類 nodes 節(jié)點類型、root 根節(jié)點信息、子節(jié)點的 WatchManager 監(jiān)控信息等數(shù)據(jù)模型中的相關(guān)信息。

        可以說,一個 DataTree 類定義了 ZooKeeper 內(nèi)存數(shù)據(jù)的邏輯結(jié)構(gòu)。

        「事務(wù)日志」

        為了整個 ZooKeeper 集群中數(shù)據(jù)的一致性,Leader 服務(wù)器會向 ZooKeeper 集群中的其他角色服務(wù)發(fā)送數(shù)據(jù)同步信息,在接收到數(shù)據(jù)同步信息后, ZooKeeper 集群中的 Follow 和 Observer 服務(wù)器就會進行數(shù)據(jù)同步。

        ?

        而這兩種角色服務(wù)器所接收到的信息就是 Leader 服務(wù)器的事務(wù)日志。

        ?

        在接收到事務(wù)日志后,并在本地服務(wù)器上執(zhí)行。這種數(shù)據(jù)同步的方式,避免了直接使用實際的業(yè)務(wù)數(shù)據(jù),減少了網(wǎng)絡(luò)傳輸?shù)拈_銷,提升了整個 ZooKeeper 集群的執(zhí)行性能。

        Watch機制

        ZooKeeper 的客戶端可以通過 Watch 機制來訂閱當服務(wù)器上某一節(jié)點的數(shù)據(jù)或狀態(tài)發(fā)生變化時收到相應(yīng)的通知;

        「如何實現(xiàn):」

        我們可以通過向 ZooKeeper 客戶端的構(gòu)造方法中傳遞 Watcher 參數(shù)的方式實現(xiàn):

        new?ZooKeeper(String?connectString,?int?sessionTimeout,?Watcher?watcher)

        上面代碼的意思是定義了一個了 ZooKeeper 客戶端對象實例,并傳入三個參數(shù):

        • connectString 服務(wù)端地址

        • sessionTimeout:超時時間

        • Watcher:監(jiān)控事件

        這個 Watcher 將作為整個 ZooKeeper 會話期間的上下文 ,一直被保存在客戶端 ZKWatchManager 的 defaultWatcher 中。

        除此之外,ZooKeeper 客戶端也可以通過 getData、exists 和 getChildren 三個接口來向 ZooKeeper 服務(wù)器注冊 Watcher,從而方便地在不同的情況下添加 Watch 事件:

        getData(String?path,?Watcher?watcher,?Stat?stat)

        觸發(fā)通知的條件:

        62e4c528e425dc5727f7ff823c415063.webp

        上圖中列出了客戶端在不同會話狀態(tài)下,相應(yīng)的在服務(wù)器節(jié)點所能支持的事件類型。

        • 例如在客戶端連接服務(wù)端的時候,可以對數(shù)據(jù)節(jié)點的創(chuàng)建、刪除、數(shù)據(jù)變更、子節(jié)點的更新等操作進行監(jiān)控。

        「當服務(wù)端某一節(jié)點發(fā)生數(shù)據(jù)變更操作時,所有曾經(jīng)設(shè)置了該節(jié)點監(jiān)控事件的客戶端都會收到服務(wù)器的通知嗎?」

        答案是否定的,Watch 事件的觸發(fā)機制取決于會話的連接狀態(tài)和客戶端注冊事件的類型,所以當客戶端會話狀態(tài)或數(shù)據(jù)節(jié)點發(fā)生改變時,都會觸發(fā)對應(yīng)的 Watch 事件。

        「訂閱發(fā)布場景實現(xiàn)」

        ?

        提到 ZooKeeper 的應(yīng)用場景,你可能第一時間會想到最為典型的發(fā)布訂閱功能。

        ?

        發(fā)布訂閱功能可以看作是一個一對多的關(guān)系,即一個服務(wù)或數(shù)據(jù)的發(fā)布者可以被多個不同的消費者調(diào)用。

        一般一個發(fā)布訂閱模式的數(shù)據(jù)交互可以分為消費者主動請求生產(chǎn)者信息的拉取模式,和生產(chǎn)者數(shù)據(jù)變更時主動推送給消費者的推送模式。

        ZooKeeper 采用了兩種模式結(jié)合的方式實現(xiàn)訂閱發(fā)布功能。

        ?

        下面我們來分析一個具體案例:

        ?

        在系統(tǒng)開發(fā)的過程中會用到各種各樣的配置信息,如數(shù)據(jù)庫配置項、第三方接口、服務(wù)地址等,這些配置操作在我們開發(fā)過程中很容易完成,但是放到一個大規(guī)模的集群中配置起來就比較麻煩了。

        通常這種集群中,我們可以用配置管理功能自動完成服務(wù)器配置信息的維護,利用ZooKeeper 的發(fā)布訂閱功能就能解決這個問題。

        我們可以把諸如數(shù)據(jù)庫配置項這樣的信息存儲在 ZooKeeper 數(shù)據(jù)節(jié)點中。

        /confs/data_item1

        • 服務(wù)器集群客戶端對該節(jié)點添加 Watch 事件監(jiān)控,當集群中的服務(wù)啟動時,會讀取該節(jié)點數(shù)據(jù)獲取數(shù)據(jù)配置信息。

        • 而當該節(jié)點數(shù)據(jù)發(fā)生變化時,ZooKeeper 服務(wù)器會發(fā)送 Watch 事件給各個客戶端,集群中的客戶端在接收到該通知后,重新讀取節(jié)點的數(shù)據(jù)庫配置信息。

        我們使用 Watch 機制實現(xiàn)了一個分布式環(huán)境下的配置管理功能,通過對 ZooKeeper 服務(wù)器節(jié)點添加數(shù)據(jù)變更事件,實現(xiàn)當數(shù)據(jù)庫配置項信息變更后,集群中的各個客戶端能接收到該變更事件的通知,并獲取最新的配置信息。

        ?

        要注意一點是,我們提到 Watch 具有一次性,所以當我們獲得服務(wù)器通知后要再次添加 Watch 事件。

        ?
        會話機制

        ZooKeeper 的工作方式一般是通過客戶端向服務(wù)端發(fā)送請求而實現(xiàn)的。

        而在一個請求的發(fā)送過程中,首先,客戶端要與服務(wù)端進行連接,而一個連接就是一個會話。

        ?

        在 ZooKeeper 中,一個會話可以看作是一個用于表示客戶端與服務(wù)器端連接的數(shù)據(jù)結(jié)構(gòu) Session。

        ?

        這個數(shù)據(jù)結(jié)構(gòu)由三個部分組成:分別是會話 ID(sessionID)、會話超時時間(TimeOut)、會話關(guān)閉狀態(tài)(isClosing)

        • 會話 ID:會話 ID 作為一個會話的標識符,當我們創(chuàng)建一次會話的時候,ZooKeeper 會自動為其分配一個唯一的 ID 編碼。

        • 會話超時時間:一般來說,一個會話的超時時間就是指一次會話從發(fā)起后到被服務(wù)器關(guān)閉的時長。而設(shè)置會話超時時間后,服務(wù)器會參考設(shè)置的超時時間,最終計算一個服務(wù)端自己的超時時間。而這個超時時間則是最終真正用于 ZooKeeper 中服務(wù)端用戶會話管理的超時時間。

        • 會話關(guān)閉狀態(tài):會話關(guān)閉 isClosing 狀態(tài)屬性字段表示一個會話是否已經(jīng)關(guān)閉。如果服務(wù)器檢查到一個會話已經(jīng)因為超時等原因失效時, ZooKeeper 會在該會話的 isClosing 屬性值標記為關(guān)閉,再之后就不對該會話進行操作了。

        「會話狀態(tài)」

        在 ZooKeeper 服務(wù)的運行過程中,會話會經(jīng)歷不同的狀態(tài)變化。

        這些狀態(tài)包括:

        ?

        正在連接(CONNECTING)、已經(jīng)連接(CONNECTIED)、正在重新連接(RECONNECTING)、已經(jīng)重新連接(RECONNECTED)、會話關(guān)閉(CLOSE)等。

        ?

        當客戶端開始創(chuàng)建一個與服務(wù)端的會話操作時,它的會話狀態(tài)就會變成 CONNECTING,之后客戶端會根據(jù)服務(wù)器地址列表中的服務(wù)器 IP 地址分別嘗試進行連接。如果遇到一個 IP 地址可以連接到服務(wù)器,那么客戶端會話狀態(tài)將變?yōu)?CONNECTIED。

        如果因為網(wǎng)絡(luò)原因造成已經(jīng)連接的客戶端會話斷開時,客戶端會重新嘗試連接服務(wù)端。而對應(yīng)的客戶端會話狀態(tài)又變成 CONNECTING ,直到該會話連接到服務(wù)端最終又變成 CONNECTIED。

        ?

        在 ZooKeeper 服務(wù)的整個運行過程中,會話狀態(tài)經(jīng)常會在 CONNECTING 與 CONNECTIED 之間進行切換。

        ?

        最后,當出現(xiàn)超時或者客戶端主動退出程序等情況時,客戶端會話狀態(tài)則會變?yōu)?CLOSE 狀態(tài)。

        「會話異?!?/strong>

        在 ZooKeeper 中,會話的超時異常包括客戶端 readtimeout 異常和服務(wù)器端 sessionTimeout 異常。

        • 在我們平時的開發(fā)中,要明確這兩個異常的不同之處在于一個是發(fā)生在客戶端,而另一個是發(fā)生在服務(wù)端。

        而對于那些對 ZooKeeper 接觸不深的開發(fā)人員來說,他們常常踩坑的地方在于,雖然設(shè)置了超時間,但是在實際服務(wù)運行的時候 ZooKeeper 并沒有按照設(shè)置的超時時間來管理會話。

        • 這是因為 ZooKeeper 實際起作用的超時時間是通過客戶端和服務(wù)端協(xié)商決定。

        ZooKeeper 客戶端在和服務(wù)端建立連接的時候,會提交一個客戶端設(shè)置的會話超時時間,而該超時時間會和服務(wù)端設(shè)置的最大超時時間和最小超時時間進行比對,如果正好在其允許的范圍內(nèi),則采用客戶端的超時時間管理會話。

        如果大于或者小于服務(wù)端設(shè)置的超時時間,則采用服務(wù)端設(shè)置的值管理會話。

        「分桶策略」

        我們知道在 ZooKeeper 中為了保證一個會話的存活狀態(tài),客戶端需要向服務(wù)器周期性地發(fā)送心跳信息。

        • 而客戶端所發(fā)送的心跳信息可以是一個 ping 請求,也可以是一個普通的業(yè)務(wù)請求。

        ZooKeeper 服務(wù)端接收請求后,會更新會話的過期時間,來保證會話的存活狀態(tài)。

        • 所以在 ZooKeeper 的會話管理中,最主要的工作就是管理會話的過期時間。
        ?

        ZooKeeper 中采用了獨特的會話管理方式來管理會話的過期時間。

        ?

        在 ZooKeeper 中,會話將按照不同的時間間隔進行劃分,超時時間相近的會話將被放在同一個間隔區(qū)間中,這種方式避免了 ZooKeeper 對每一個會話進行檢查,而是采用分批次的方式管理會話。

        這就降低了會話管理的難度,因為每次小批量的處理會話過期也提高了會話處理的效率。

        「ZooKeeper 這種會話管理的好處?」

        ZooKeeper 這種分段的會話管理策略大大提高了計算會話過期的效率,如果是在一個實際生產(chǎn)環(huán)境中,一個大型的分布式系統(tǒng)往往具有很高的訪問量。

        而 ZooKeeper 作為其中的組件,對外提供服務(wù)往往要承擔(dān)數(shù)千個客戶端的訪問,這其中就要對這幾千個會話進行管理。

        在這種場景下,要想通過對每一個會話進行管理和檢查并不合適,所以采用將同一個時間段的會話進行統(tǒng)一管理,這樣就大大提高了服務(wù)的運行效率。

        「底層實現(xiàn)」

        ZooKeeper 底層實現(xiàn)的原理,核心的一點就是過期隊列這個數(shù)據(jù)結(jié)構(gòu)。所有會話過期的相關(guān)操作都是圍繞這個隊列進行的。

        • 可以說 ZooKeeper 底層就是采用這個隊列結(jié)構(gòu)來管理會話過期的。

        「一個會話過期隊列是由若干個 bucket 組成的。」

        • bucket 是一個按照時間劃分的區(qū)間。

        • 在 ZooKeeper 中,通常以 expirationInterval 為單位進行時間區(qū)間的劃分,它是 ZooKeeper 分桶策略中用于劃分時間區(qū)間的最小單位。

        • 在 ZooKeeper 中,一個過期隊列由不同的 bucket 組成。

        • 每個 bucket 中存放了在某一時間內(nèi)過期的會話。

        將會話按照不同的過期時間段分別維護到過期隊列之后,在 ZooKeeper 服務(wù)運行的過程中,具體的執(zhí)行過程如下圖所示。

        c748d7e1f3bc243f08d01e8c2f5f7194.webp

        首先,ZooKeeper 服務(wù)會開啟一個線程專門用來檢索過期隊列,找出要過期的 bucket,而 ZooKeeper 每次只會讓一個 bucket 的會話過期,每當要進行會話過期操作時,ZooKeeper 會喚醒一個處于休眠狀態(tài)的線程進行會話過期操作,之后會按照上面介紹的操作檢索過期隊列,取出過期的會話后會執(zhí)行過期操作。

        ACL權(quán)限

        ZooKeeper的ACL可針對znodes設(shè)置相應(yīng)的權(quán)限信息。

        一個 ACL 權(quán)限設(shè)置通??梢苑譃?3 部分,分別是:權(quán)限模式(Scheme)、授權(quán)對象(ID)、權(quán)限信息(Permission)。

        • 最終組成一條例如scheme:id:permission格式的 ACL 請求信息。

        「權(quán)限模式:Scheme」

        ZooKeeper 的權(quán)限驗證方式大體分為兩種類型,一種是范圍驗證,另外一種是口令驗證。

        ?

        范圍驗證

        ?

        所謂的范圍驗證就是說 ZooKeeper 可以針對一個 IP 或者一段 IP 地址授予某種權(quán)限。

        比如我們可以讓一個 IP 地址為ip:192.168.0.11的機器對服務(wù)器上的某個數(shù)據(jù)節(jié)點具有寫入的權(quán)限。

        或者也可以通過ip:192.168.0.11/22給一段 IP 地址的機器賦權(quán)。

        ?

        口令驗證

        ?

        可以理解為用戶名密碼的方式,這是我們最熟悉也是日常生活中經(jīng)常使用的模式,比如我們打開自己的電腦或者去銀行取錢都需要提供相應(yīng)的密碼。

        在 ZooKeeper 中這種驗證方式是 Digest 認證,我們知道通過網(wǎng)絡(luò)傳輸相對來說并不安全,所以絕不通過明文在網(wǎng)絡(luò)發(fā)送密碼也是程序設(shè)計中很重要的原則之一,而 Digest 這種認證方式首先在客戶端傳送username:password這種形式的權(quán)限表示符后,ZooKeeper 服務(wù)端會對密碼部分使用 SHA-1 和 BASE64 算法進行加密,以保證安全性。

        ?

        Super 權(quán)限模式

        ?

        權(quán)限模式 Super 可以認為是一種特殊的 Digest 認證。

        具有 Super 權(quán)限的客戶端可以對 ZooKeeper 上的任意數(shù)據(jù)節(jié)點進行任意操作。

        下面這段代碼給出了 Digest 模式下客戶端的調(diào)用方式。

        //創(chuàng)建節(jié)點
        create?/digest_node1
        //設(shè)置digest權(quán)限驗證
        setAcl?/digest_node1?digest:用戶名:base64格式密碼:rwadc?
        //查詢節(jié)點Acl權(quán)限
        getAcl?/digest_node1?
        //授權(quán)操作
        addauth?digest?user:passwd
        ?

        如果一個客戶端對服務(wù)器上的一個節(jié)點設(shè)置了只有它自己才能操作的權(quán)限,那么等這個客戶端下線或被刪除后。

        ?

        對其創(chuàng)建的節(jié)點要想進行修改應(yīng)該怎么做呢?

        我們可以通過「super 模式」即超級管理員的方式刪除該節(jié)點或變更該節(jié)點的權(quán)限驗證方式。

        正因為「super 模式」有如此大的權(quán)限,我們在平時使用時也應(yīng)該更加謹慎。

        ?

        world 模式

        ?

        這種授權(quán)模式對應(yīng)于系統(tǒng)中的所有用戶,本質(zhì)上起不到任何作用。

        設(shè)置了 world 權(quán)限模式系統(tǒng)中的所有用戶操作都可以不進行權(quán)限驗證。

        「授權(quán)對象(ID)」

        所謂的授權(quán)對象就是說我們要把權(quán)限賦予誰,而對應(yīng)于 4 種不同的權(quán)限模式來說,如果我們選擇采用 IP 方式,使用的授權(quán)對象可以是一個 IP 地址或 IP 地址段;而如果使用 Digest 或 Super 方式,則對應(yīng)于一個用戶名。

        如果是 World 模式,是授權(quán)系統(tǒng)中所有的用戶。

        「權(quán)限信息(Permission)」

        權(quán)限就是指我們可以在數(shù)據(jù)節(jié)點上執(zhí)行的操作種類,在 ZooKeeper 中已經(jīng)定義好的權(quán)限有 5 種:

        • 數(shù)據(jù)節(jié)點(create)創(chuàng)建權(quán)限,授予權(quán)限的對象可以在數(shù)據(jù)節(jié)點下創(chuàng)建子節(jié)點;

        • 數(shù)據(jù)節(jié)點(wirte)更新權(quán)限,授予權(quán)限的對象可以更新該數(shù)據(jù)節(jié)點;

        • 數(shù)據(jù)節(jié)點(read)讀取權(quán)限,授予權(quán)限的對象可以讀取該節(jié)點的內(nèi)容以及子節(jié)點的信息;

        • 數(shù)據(jù)節(jié)點(delete)刪除權(quán)限,授予權(quán)限的對象可以刪除該數(shù)據(jù)節(jié)點的子節(jié)點;

        • 數(shù)據(jù)節(jié)點(admin)管理者權(quán)限,授予權(quán)限的對象可以對該數(shù)據(jù)節(jié)點體進行 ACL 權(quán)限設(shè)置。

        ?

        需要注意的一點是,每個節(jié)點都有維護自身的 ACL 權(quán)限數(shù)據(jù),即使是該節(jié)點的子節(jié)點也是有自己的 ACL 權(quán)限而不是直接繼承其父節(jié)點的權(quán)限。

        ?

        「實現(xiàn)自己的權(quán)限口控制」

        雖然 ZooKeeper 自身的權(quán)限控制機制已經(jīng)做得很細,但是它還是提供了一種權(quán)限擴展機制來讓用戶實現(xiàn)自己的權(quán)限控制方式。

        官方文檔中對這種機制的定義是 Pluggable ZooKeeper Authenication,意思是可插拔的授權(quán)機制,從名稱上我們可以看出它的靈活性。那么這種機制是如何實現(xiàn)的呢?

        ?

        要想實現(xiàn)自定義的權(quán)限控制機制,最核心的一點是實現(xiàn) ZooKeeper 提供的權(quán)限控制器接口 AuthenticationProvider。

        ?

        實現(xiàn)了自定義權(quán)限后,如何才能讓 ZooKeeper 服務(wù)端使用自定義的權(quán)限驗證方式呢?

        接下來就需要將自定義的權(quán)限控制注冊到 ZooKeeper 服務(wù)器中,而注冊的方式通常有兩種。

        • 第一種是通過設(shè)置系統(tǒng)屬性來注冊自定義的權(quán)限控制器:
        -Dzookeeper.authProvider.x=CustomAuthenticationProvider
        • 另一種是在配置文件zoo.cfg中進行配置:
        authProvider.x=CustomAuthenticationProvider

        「實現(xiàn)原理」

        首先是封裝該請求的類型,之后將權(quán)限信息封裝到 request 中并發(fā)送給服務(wù)端。而服務(wù)器的實現(xiàn)比較復(fù)雜,首先分析請求類型是否是權(quán)限相關(guān)操作,之后根據(jù)不同的權(quán)限模式(scheme)調(diào)用不同的實現(xiàn)類驗證權(quán)限最后存儲權(quán)限信息。

        在授權(quán)接口中,值得注意的是會話的授權(quán)信息存儲在 ZooKeeper 服務(wù)端的內(nèi)存中,如果客戶端會話關(guān)閉,授權(quán)信息會被刪除。

        下次連接服務(wù)器后,需要重新調(diào)用授權(quán)接口進行授權(quán)。

        序列化方式

        在 ZooKeeper 中并沒有采用和 Java 一樣的序列化方式,而是采用了一個 Jute 的序列解決方案作為 ZooKeeper 框架自身的序列化方式。

        ?

        ZooKeeper 從最開始就采用 Jute 作為其序列化解決方案,直到其最新的版本依然沒有更改。

        ?

        雖然 ZooKeeper 一直將 Jute 框架作為序列化解決方案,但這并不意味著 Jute 相對其他框架性能更好,反倒是 Apache Avro、Thrift 等框架在性能上優(yōu)于前者。

        之所以 ZooKeeper 一直采用 Jute 作為序列化解決方案,主要是新老版本的兼容等問題。

        「如何 使用 Jute 實現(xiàn)序列化」

        如果我們要想將某個定義的類進行序列化,首先需要該類實現(xiàn) Record 接口的 serilize 和 deserialize 方法,這兩個方法分別是序列化和反序列化方法。

        ?

        下邊這段代碼給出了我們一般在 ZooKeeper 中進行序列化的具體實現(xiàn):

        ?

        首先,我們定義了一個test_jute類,為了能夠?qū)λM行序列化,需要該test_jute類實現(xiàn) Record 接口,并在對應(yīng)的 serialize 序列化方法和 deserialize 反序列化方法中編輯具體的實現(xiàn)邏輯。

        class?test_jute?implements?Record{
        ??private?long?ids;
        ??private?String?name;
        ??...
        ??public?void?serialize(OutpurArchive?a_,String?tag){
        ????...
        ??}
        ??public?void?deserialize(INputArchive?a_,String?tag){
        ????...
        ??}
        }

        在序列化方法 serialize 中,我們要實現(xiàn)的邏輯是,首先通過字符類型參數(shù) tag 傳遞標記序列化標識符,之后使用 writeLong 和 writeString 等方法分別將對象屬性字段進行序列化。

        public?void?serialize(OutpurArchive?a_,String?tag)?throws?...{
        ??a_.startRecord(this.tag);
        ??a_.writeLong(ids,"ids");
        ??a_.writeString(type,"name");
        ??a_.endRecord(this,tag);
        }

        調(diào)用 derseralize 在實現(xiàn)反序列化的過程則與我們上邊說的序列化過程正好相反。

        public?void?deserialize(INputArchive?a_,String?tag)?throws?{
        ??a_.startRecord(tag);
        ??ids?=?a_.readLong("ids");
        ??name?=?a_.readString("name");
        ??a_.endRecord(tag);
        }

        序列化和反序列化的實現(xiàn)邏輯編碼方式相對固定,首先通過 startRecord 開啟一段序列化操作,之后通過 writeLong、writeString 或 readLong、 readString 等方法執(zhí)行序列化或反序列化。

        本例中只是實現(xiàn)了長整型和字符型的序列化和反序列化操作,除此之外 ZooKeeper 中的 Jute 框架還支持整數(shù)類型(Int)、布爾類型(Bool)、雙精度類型(Double)以及 Byte/Buffer 類型。

        集群

        「ZooKeeper集群模式的特點」

        在 ZooKeeper 集群中將服務(wù)器分成 「Leader 、Follow 、Observer 三」種角色服務(wù)器,在集群運行期間這三種服務(wù)器所負責(zé)的工作各不相同:

        • Leader 角色服務(wù)器負責(zé)管理集群中其他的服務(wù)器,是集群中工作的分配和調(diào)度者,既可以為客戶端提供寫服務(wù)又能提供讀服務(wù)。

        • Follow 服務(wù)器的主要工作是選舉出 Leader 服務(wù)器,在發(fā)生 Leader 服務(wù)器選舉的時候,系統(tǒng)會從 Follow 服務(wù)器之間根據(jù)多數(shù)投票原則,選舉出一個 Follow 服務(wù)器作為新的 Leader 服務(wù)器,只能提供讀服務(wù)。

        • Observer 服務(wù)器則主要負責(zé)處理來自客戶端的獲取數(shù)據(jù)等請求,并不參與 Leader 服務(wù)器的選舉操作,也不會作為候選者被選舉為 Leader 服務(wù)器,只能提供讀服務(wù)。

        在 ZooKeeper 集群接收到來自客戶端的會話請求操作后,首先會判斷該條請求是否是事務(wù)性的會話請求。

        ?

        對于事務(wù)性的會話請求,ZooKeeper 集群服務(wù)端會將該請求統(tǒng)一轉(zhuǎn)發(fā)給 Leader 服務(wù)器進行操作。

        所謂事務(wù)性請求,是指 ZooKeeper 服務(wù)器執(zhí)行完該條會話請求后,是否會導(dǎo)致執(zhí)行該條會話請求的服務(wù)器的數(shù)據(jù)或狀態(tài)發(fā)生改變,進而導(dǎo)致與其他集群中的服務(wù)器出現(xiàn)數(shù)據(jù)不一致的情況。

        ?

        Leader 服務(wù)器內(nèi)部執(zhí)行該條事務(wù)性的會話請求后,再將數(shù)據(jù)同步給其他角色服務(wù)器,從而保證事務(wù)性會話請求的執(zhí)行順序,進而保證整個 ZooKeeper 集群的數(shù)據(jù)一致性。

        ?

        在 ZooKeeper 集群的內(nèi)部實現(xiàn)中,是通過什么方法保證所有 ZooKeeper 集群接收到的事務(wù)性會話請求都能交給 Leader 服務(wù)器進行處理的呢?

        ?

        在 ZooKeeper 集群內(nèi)部,集群中除 Leader 服務(wù)器外的其他角色服務(wù)器接收到來自客戶端的事務(wù)性會話請求后,必須將該條會話請求轉(zhuǎn)發(fā)給 Leader 服務(wù)器進行處理。

        ZooKeeper 集群中的 Follow 和 Observer 服務(wù)器,都會檢查當前接收到的會話請求是否是事務(wù)性的請求,如果是事務(wù)性的請求,那么就將該請求以 REQUEST 消息類型轉(zhuǎn)發(fā)給 Leader 服務(wù)器。

        在 ZooKeeper集群中的服務(wù)器接收到該條消息后,會對該條消息進行解析。

        • 分析出該條消息所包含的原始客戶端會話請求。

        • 之后將該條消息提交到自己的 Leader 服務(wù)器請求處理鏈中,開始進行事務(wù)性的會話請求操作。

        • 如果不是事務(wù)性請求,ZooKeeper 集群則交由 Follow 和 Observer 角色服務(wù)器處理該條會話請求,如查詢數(shù)據(jù)節(jié)點信息。

        當一個業(yè)務(wù)場景在查詢操作多而創(chuàng)建刪除等事務(wù)性操作少的情況下,ZooKeeper 集群的性能表現(xiàn)的就會很好。

        ?

        如果是在極端情況下,ZooKeeper 集群只有事務(wù)性的會話請求而沒有查詢操作,那么 Follow 和 Observer 服務(wù)器就只能充當一個請求轉(zhuǎn)發(fā)服務(wù)器的角色, 所有的會話的處理壓力都在 Leader 服務(wù)器。

        ?

        在處理性能上整個集群服務(wù)器的瓶頸取決于 Leader 服務(wù)器的性能。

        ?

        ZooKeeper 集群的作用只能保證在 Leader 節(jié)點崩潰的時候,重新選舉出 Leader 服務(wù)器保證系統(tǒng)的穩(wěn)定性。

        ?

        這也是 ZooKeeper 設(shè)計的一個缺點。

        「Leader選舉」

        Leader 服務(wù)器的選舉操作主要發(fā)生在兩種情況下。

        第一種就是 ZooKeeper 集群服務(wù)啟動的時候,第二種就是在 ZooKeeper 集群中舊的 Leader 服務(wù)器失效時,這時 ZooKeeper 集群需要選舉出新的 Leader 服務(wù)器。

        ?

        ZooKeeper 集群重新選舉 Leader 的過程只有 Follow 服務(wù)器參與工作。

        ?
        ?

        服務(wù)器狀態(tài)

        ?

        服務(wù)器具有四種狀態(tài),分別是LOOKING、FOLLOWING、LEADING、OBSERVING。

        • 「LOOKING」:尋找Leader狀態(tài)。當服務(wù)器處于該狀態(tài)時,它會認為當前集群中沒有Leader,因此需要進入Leader選舉狀態(tài)。

        • 「FOLLOWING」:跟隨者狀態(tài)。表明當前服務(wù)器角色是Follower。

        • 「LEADING」:領(lǐng)導(dǎo)者狀態(tài)。表明當前服務(wù)器角色是Leader。

        • 「OBSERVING」:觀察者狀態(tài)。表明當前服務(wù)器角色是Observer。

        「事務(wù)ID(zxid)」

        Zookeeper的狀態(tài)變化,都會由一個Zookeeper事務(wù)ID(ZXID)標識。

        ?

        寫入Zookeeper,會導(dǎo)致狀態(tài)變化,每次寫入都會導(dǎo)致ZXID發(fā)生變化。

        ?

        ZXID由Leader統(tǒng)一分配,全局唯一,長度64位,遞增。

        ZXID展示了所有的Zookeeper轉(zhuǎn)臺變更順序,每次變更都有一個唯一ZXID,如果zxid1小于zxid2,則說明zxid1的事務(wù)在zxid2的事務(wù)之前發(fā)生。

        「選舉過程」

        在 ZooKeeper 集群重新選舉 Leader 節(jié)點的過程中,主要可以分為 Leader 失效發(fā)現(xiàn)、重新選舉 Leader 、Follow 服務(wù)器角色變更、集群同步這幾個步驟。

        ?

        Leader 失效發(fā)現(xiàn)

        ?

        在 ZooKeeper 集群中,當 Leader 服務(wù)器失效時,ZooKeeper 集群會重新選舉出新的 Leader 服務(wù)器。

        • 在 ZooKeeper 集群中,探測 Leader 服務(wù)器是否存活的方式與保持客戶端活躍性的方法非常相似。

        首先,F(xiàn)ollow 服務(wù)器會定期向 Leader 服務(wù)器發(fā)送 網(wǎng)絡(luò)請求,在接收到請求后,Leader 服務(wù)器會返回響應(yīng)數(shù)據(jù)包給 Follow 服務(wù)器,而在 Follow 服務(wù)器接收到 Leader 服務(wù)器的響應(yīng)后,如果判斷 Leader 服務(wù)器運行正常,則繼續(xù)進行數(shù)據(jù)同步和服務(wù)轉(zhuǎn)發(fā)等工作,反之,則進行 Leader 服務(wù)器的重新選舉操作。

        ?

        Leader重新選舉

        ?

        當 Follow 服務(wù)器向 Leader 服務(wù)器發(fā)送狀態(tài)請求包后,如果沒有得到 Leader 服務(wù)器的返回信息,這時,如果是集群中個別的 Follow 服務(wù)器發(fā)現(xiàn)返回錯誤,并不會導(dǎo)致 ZooKeeper 集群立刻重新選舉 Leader 服務(wù)器,而是將該 Follow 服務(wù)器的狀態(tài)變更為 LOOKING 狀態(tài),并向網(wǎng)絡(luò)中發(fā)起投票,當 ZooKeeper 集群中有更多的機器發(fā)起投票,最后當投票結(jié)果滿足多數(shù)原則的情況下。

        ZooKeeper 會重新選舉出 Leader 服務(wù)器。

        ?

        Follow 角色變更

        ?

        在 ZooKeeper 集群中,F(xiàn)ollow 服務(wù)器作為 Leader 服務(wù)器的候選者,當被選舉為 Leader 服務(wù)器之后,其在 ZooKeeper 集群中的 Follow 角色,也隨之發(fā)生改變。也就是要轉(zhuǎn)變?yōu)?Leader 服務(wù)器,并作為 ZooKeeper 集群中的 Leader 角色服務(wù)器對外提供服務(wù)。

        ?

        集群同步數(shù)據(jù)

        ?

        在 ZooKeeper 集群成功選舉 Leader 服務(wù)器,并且候選 Follow 服務(wù)器的角色變更后。

        為避免在這期間導(dǎo)致的數(shù)據(jù)不一致問題,ZooKeeper 集群在對外提供服務(wù)之前,會通過 Leader 角色服務(wù)器管理同步其他角色服務(wù)器。

        「底層實現(xiàn)」

        首先,ZooKeeper 集群會先判斷 Leader 服務(wù)器是否失效,而判斷的方式就是 Follow 服務(wù)器向 Leader 服務(wù)器發(fā)送請求包,之后 Follow 服務(wù)器接收到響應(yīng)數(shù)據(jù)后,進行解析,F(xiàn)ollow 服務(wù)器會根據(jù)返回的數(shù)據(jù),判斷 Leader 服務(wù)器的運行狀態(tài),如果返回的是 LOOKING 關(guān)鍵字,表明與集群中 Leader 服務(wù)器無法正常通信。

        • 之后,在 ZooKeeper 集群選舉 Leader 服務(wù)器時,是通過 「FastLeaderElection」 類實現(xiàn)的。

        該類實現(xiàn)了 TCP 方式的通信連接,用于在 ZooKeeper 集群中與其他 Follow 服務(wù)器進行協(xié)調(diào)溝通。

        FastLeaderElection 類繼承了 Election 接口,定義其是用來進行選舉的實現(xiàn)類。

        • 而在其內(nèi)部,又定義了選舉通信相關(guān)的一些配置參數(shù),比如 finalizeWait 最終等待時間、最大通知間隔時間 maxNotificationInterval 等。

        在選舉的過程中,首先調(diào)用 ToSend 函數(shù)向 ZooKeeper 集群中的其他角色服務(wù)器發(fā)送本機的投票信息,其他服務(wù)器在接收投票信息后,會對投票信息進行有效性驗證等操作,之后 ZooKeeper 集群統(tǒng)計投票信息,如果過半數(shù)的機器投票信息一致,則集群就重新選出新的 Leader 服務(wù)器。

        ?

        這里我們要注意一個問題,那就是在重新選舉 Leader 服務(wù)器的過程中,ZooKeeper 集群理論上是無法進行事務(wù)性的請求處理的。

        ?

        因此,發(fā)送到 ZooKeeper 集群中的事務(wù)性會話會被掛起,暫時不執(zhí)行,等到選舉出新的 Leader 服務(wù)器后再進行操作。

        「Observer」

        在 ZooKeeper 集群服務(wù)運行的過程中,Observer 服務(wù)器與 Follow 服務(wù)器具有一個相同的功能,那就是負責(zé)處理來自客戶端的諸如查詢數(shù)據(jù)節(jié)點等非事務(wù)性的會話請求操作。

        • 但與 Follow 服務(wù)器不同的是,Observer 不參與 Leader 服務(wù)器的選舉工作,也不會被選舉為 Leader 服務(wù)器。

        在早期的 ZooKeeper 集群服務(wù)運行過程中,只有 Leader 服務(wù)器和 Follow 服務(wù)器。

        不過隨著 ZooKeeper 在分布式環(huán)境下的廣泛應(yīng)用,早期模式的設(shè)計缺點也隨之產(chǎn)生,主要帶來的問題有如下幾點:

        • 隨著集群規(guī)模的變大,集群處理寫入的性能反而下降。

        • ZooKeeper 集群無法做到跨域部署。

        其中最主要的問題在于,當 ZooKeeper 集群的規(guī)模變大,集群中 Follow 服務(wù)器數(shù)量逐漸增多的時候,ZooKeeper 處理創(chuàng)建數(shù)據(jù)節(jié)點等事務(wù)性請求操作的性能就會逐漸下降。

        這是因為 ZooKeeper 集群在處理事務(wù)性請求操作時,要在 ZooKeeper 集群中對該事務(wù)性的請求發(fā)起投票,只有超過半數(shù)的 Follow 服務(wù)器投票一致,才會執(zhí)行該條寫入操作。

        正因如此,隨著集群中 Follow 服務(wù)器的數(shù)量越來越多,一次寫入等相關(guān)操作的投票也就變得越來越復(fù)雜,并且 Follow 服務(wù)器之間彼此的網(wǎng)絡(luò)通信也變得越來越耗時,導(dǎo)致隨著 Follow 服務(wù)器數(shù)量的逐步增加,事務(wù)性的處理性能反而變得越來越低。

        • 為了解決這一問題,在 ZooKeeper 3.6 版本后,ZooKeeper 集群中創(chuàng)建了一種新的服務(wù)器角色,即 Observer——觀察者角色服務(wù)器。

        Observer 可以處理 ZooKeeper 集群中的非事務(wù)性請求,并且不參與 Leader 節(jié)點等投票相關(guān)的操作。

        這樣既保證了 ZooKeeper 集群性能的擴展性,又避免了因為過多的服務(wù)器參與投票相關(guān)的操作而影響 ZooKeeper 集群處理事務(wù)性會話請求的能力。

        • 在實際部署的時候,因為 Observer 不參與 Leader 節(jié)點等操作,并不會像 Follow 服務(wù)器那樣頻繁的與 Leader 服務(wù)器進行通信。

        因此,可以將 Observer 服務(wù)器部署在不同的網(wǎng)絡(luò)區(qū)間中,這樣也不會影響整個 ZooKeeper 集群的性能,也就是所謂的跨域部署。

        「在我們?nèi)粘J褂?ZooKeeper 集群服務(wù)器的時候,集群中的機器個數(shù)應(yīng)該選擇奇數(shù)個?」

        兩個原因:

        ?

        在容錯能力相同的情況下,奇數(shù)臺更節(jié)省資源

        ?

        Zookeeper中 Leader 選舉算法采用了Zab協(xié)議。

        Zab核心思想是當多數(shù) Server 寫成功,則寫成功。

        舉兩個例子:

        • 假如zookeeper集群1 ,有3個節(jié)點,3/2=1.5 , ?即zookeeper想要正常對外提供服務(wù)(即leader選舉成功),至少需要2個節(jié)點是正常的。換句話說,3個節(jié)點的zookeeper集群,允許有一個節(jié)點宕機。

        • 假如zookeeper集群2,有4個節(jié)點,4/2=2 , 即zookeeper想要正常對外提供服務(wù)(即leader選舉成功),至少需要3個節(jié)點是正常的。換句話說,4個節(jié)點的zookeeper集群,也允許有一個節(jié)點宕機。

        集群1與集群2都有 允許1個節(jié)點宕機 的容錯能力,但是集群2比集群1多了1個節(jié)點。在相同容錯能力的情況下,本著節(jié)約資源的原則,zookeeper集群的節(jié)點數(shù)維持奇數(shù)個更好一些。

        ?

        防止由腦裂造成的集群不可用。

        ?

        集群的腦裂通常是發(fā)生在節(jié)點之間通信不可達的情況下,集群會分裂成不同的小集群,小集群各自選出自己的master節(jié)點,導(dǎo)致原有的集群出現(xiàn)多個master節(jié)點的情況,這就是腦裂。

        下面舉例說一下為什么采用奇數(shù)臺節(jié)點,就可以防止由于腦裂造成的服務(wù)不可用:

        假如zookeeper集群有 5 個節(jié)點,發(fā)生了腦裂,腦裂成了A、B兩個小集群:

        • A :1個節(jié)點 ,B :4個節(jié)點

        • A :2個節(jié)點, B :3個節(jié)點

        可以看出,上面這兩種情況下,A、B中總會有一個小集群滿足 可用節(jié)點數(shù)量 > 總節(jié)點數(shù)量/2 。

        所以zookeeper集群仍然能夠選舉出leader , 仍然能對外提供服務(wù),只不過是有一部分節(jié)點失效了而已。

        假如zookeeper集群有4個節(jié)點,同樣發(fā)生腦裂,腦裂成了A、B兩個小集群:

        • A:1個節(jié)點 , ?B:3個節(jié)點

        • A:2個節(jié)點 , B:2個節(jié)點

        因為A和B都是2個節(jié)點,都不滿足 可用節(jié)點數(shù)量 > 總節(jié)點數(shù)量/2 的選舉條件, 所以此時zookeeper就徹底不能提供服務(wù)了。

        ZAB協(xié)議

        「ZAB 協(xié)議算法」

        ZooKeeper 最核心的作用就是保證分布式系統(tǒng)的數(shù)據(jù)一致性,而無論是處理來自客戶端的會話請求時,還是集群 Leader 節(jié)點發(fā)生重新選舉時,都會產(chǎn)生數(shù)據(jù)不一致的情況。

        ?

        為了解決這個問題,ZooKeeper 采用了 ZAB 協(xié)議算法。

        ?

        ZAB 協(xié)議算法(Zookeeper Atomic Broadcast ?,Zookeeper 原子廣播協(xié)議)是 ZooKeeper 專門設(shè)計用來解決集群最終一致性問題的算法,它的兩個核心功能點是崩潰恢復(fù)和原子廣播協(xié)議。

        • 在整個 ZAB 協(xié)議的底層實現(xiàn)中,ZooKeeper 集群主要采用主從模式的系統(tǒng)架構(gòu)方式來保證 ZooKeeper 集群系統(tǒng)的一致性。

        當接收到來自客戶端的事務(wù)性會話請求后,系統(tǒng)集群采用主服務(wù)器來處理該條會話請求,經(jīng)過主服務(wù)器處理的結(jié)果會通過網(wǎng)絡(luò)發(fā)送給集群中其他從節(jié)點服務(wù)器進行數(shù)據(jù)同步操作。

        ?

        以 ZooKeeper 集群為例,這個操作過程可以概括為:

        ?

        當 ZooKeeper 集群接收到來自客戶端的事務(wù)性的會話請求后,集群中的其他 Follow 角色服務(wù)器會將該請求轉(zhuǎn)發(fā)給 Leader 角色服務(wù)器進行處理。

        當 Leader 節(jié)點服務(wù)器在處理完該條會話請求后,會將結(jié)果通過操作日志的方式同步給集群中的 Follow 角色服務(wù)器。

        然后 Follow 角色服務(wù)器根據(jù)接收到的操作日志,在本地執(zhí)行相關(guān)的數(shù)據(jù)處理操作,最終完成整個 ZooKeeper 集群對客戶端會話的處理工作。

        「崩潰恢復(fù)」

        當集群中的 Leader 發(fā)生故障的時候,整個集群就會因為缺少 Leader 服務(wù)器而無法處理來自客戶端的事務(wù)性的會話請求。

        ?

        因此,為了解決這個問題。在 ZAB 協(xié)議中也設(shè)置了處理該問題的崩潰恢復(fù)機制。

        ?

        崩潰恢復(fù)機制是保證 ZooKeeper 集群服務(wù)高可用的關(guān)鍵。觸發(fā) ZooKeeper 集群執(zhí)行崩潰恢復(fù)的事件是集群中的 Leader 節(jié)點服務(wù)器發(fā)生了異常而無法工作,于是 Follow 服務(wù)器會通過投票來決定是否選出新的 Leader 節(jié)點服務(wù)器。

        ?

        投票過程如下:

        ?

        當崩潰恢復(fù)機制開始的時候,整個 ZooKeeper 集群的每臺 Follow 服務(wù)器會發(fā)起投票,并同步給集群中的其他 Follow 服務(wù)器。

        在接收到來自集群中的其他 Follow 服務(wù)器的投票信息后,集群中的每個 Follow 服務(wù)器都會與自身的投票信息進行對比,如果判斷新的投票信息更合適,則采用新的投票信息作為自己的投票信息。在集群中的投票信息還沒有達到超過半數(shù)原則的情況下,再進行新一輪的投票,最終當整個 ZooKeeper 集群中的 Follow 服務(wù)器超過半數(shù)投出的結(jié)果相同的時候,就會產(chǎn)生新的 Leader 服務(wù)器。

        ?

        選票結(jié)構(gòu):

        ?

        以 Fast Leader Election 選舉的實現(xiàn)方式來講,如下圖所示,一個選票的整體結(jié)果可以分為一下六個部分:

        bbbd5b480151e20b9d90f29f10b61aa5.webp
        • logicClock:用來記錄服務(wù)器的投票輪次。logicClock 會從 1 開始計數(shù),每當該臺服務(wù)經(jīng)過一輪投票后,logicClock 的數(shù)值就會加 1 。

        • state:用來標記當前服務(wù)器的狀態(tài)。在 ZooKeeper 集群中一臺服務(wù)器具有 LOOKING、FOLLOWING、LEADERING、OBSERVING 這四種狀態(tài)。

        • self_id:用來表示當前服務(wù)器的 ID 信息,該字段在 ZooKeeper 集群中主要用來作為服務(wù)器的身份標識符。

        • self_zxid:當前服務(wù)器上所保存的數(shù)據(jù)的最大事務(wù) ID ,從 0 開始計數(shù)。

        • vote_id:投票要被推舉的服務(wù)器的唯一 ID 。

        • vote_zxid:被推舉的服務(wù)器上所保存的數(shù)據(jù)的最大事務(wù) ID ,從 0 開始計數(shù)。

        當 ZooKeeper 集群需要重新選舉出新的 Leader 服務(wù)器的時候,就會根據(jù)上面介紹的投票信息內(nèi)容進行對比,以找出最適合的服務(wù)器。

        ?

        選票篩選

        ?

        當一臺 Follow 服務(wù)器接收到網(wǎng)絡(luò)中的其他 Follow 服務(wù)器的投票信息后,是如何進行對比來更新自己的投票信息的。

        Follow 服務(wù)器進行選票對比的過程,如下圖所示。

        f66021ab970da33aee55f7e1d0623d9c.webp

        首先,會對比 logicClock 服務(wù)器的投票輪次,當 logicClock 相同時,表明兩張選票處于相同的投票階段,并進入下一階段,否則跳過。

        接下來再對比vote_zxid被選舉的服務(wù)器 ID 信息,若接收到的外部投票信息中的 vote_zxid字段較大,則將自己的票中的vote_zxidvote_myid更新為收到的票中的vote_zxidvote_myid ,并廣播出去。

        要是對比的結(jié)果相同,則繼續(xù)對比vote_myid被選舉服務(wù)器上所保存的最大事務(wù) ID ,若外部投票的vote_myid 比較大,則將自己的票中的 vote_myid更新為收到的票中的vote_myid

        經(jīng)過這些對比和替換后,最終該臺 Follow 服務(wù)器會產(chǎn)生新的投票信息,并在下一輪的投票中發(fā)送到 ZooKeeper 集群中。

        「消息廣播」

        在 Leader 節(jié)點服務(wù)器處理請求后,需要通知集群中的其他角色服務(wù)器進行數(shù)據(jù)同步。ZooKeeper 集群采用消息廣播的方式發(fā)送通知。

        ZooKeeper 集群使用原子廣播協(xié)議進行消息發(fā)送,該協(xié)議的底層實現(xiàn)過程與二階段提交過程非常相似,如下圖所示。

        68a1047a1f9ba19cc7c14eb8d9351e91.webp

        當要在集群中的其他角色服務(wù)器進行數(shù)據(jù)同步的時候,Leader 服務(wù)器將該操作過程封裝成一個 Proposal 提交事務(wù),并將其發(fā)送給集群中其他需要進行數(shù)據(jù)同步的服務(wù)器。

        當這些服務(wù)器接收到 Leader 服務(wù)器的數(shù)據(jù)同步事務(wù)后,會將該條事務(wù)能否在本地正常執(zhí)行的結(jié)果反饋給 Leader 服務(wù)器,Leader 服務(wù)器在接收到其他 Follow 服務(wù)器的反饋信息后進行統(tǒng)計,判斷是否在集群中執(zhí)行本次事務(wù)操作。

        這里請注意 ,與二階段提交過程不同(即需要集群中所有服務(wù)器都反饋可以執(zhí)行事務(wù)操作后,主服務(wù)器再次發(fā)送 commit 提交請求執(zhí)行數(shù)據(jù)變更) ,ZAB 協(xié)議算法省去了中斷的邏輯,當 ZooKeeper 集群中有超過一半的 Follow 服務(wù)器能夠正常執(zhí)行事務(wù)操作后,整個 ZooKeeper 集群就可以提交 Proposal 事務(wù)了。

        日志清理

        「日志類型」

        在 ZooKeeper 服務(wù)運行的時候,一般會產(chǎn)生數(shù)據(jù)快照和日志文件,數(shù)據(jù)快照用于集群服務(wù)中的數(shù)據(jù)同步,而數(shù)據(jù)日志則記錄了 ZooKeeper 服務(wù)運行的相關(guān)狀態(tài)信息。

        ?

        其中,數(shù)據(jù)日志是我們在生產(chǎn)環(huán)境中需要定期維護和管理的文件。

        ?

        「清理方案」

        如上面所介紹的,面對生產(chǎn)系統(tǒng)中產(chǎn)生的日志,一般的維護操作是備份和清理。

        備份是為了之后對系統(tǒng)的運行情況進行排查和優(yōu)化,而清理主要因為隨著系統(tǒng)日志的增加,日志會逐漸占用系統(tǒng)的存儲空間,如果一直不進行清理,可能耗盡系統(tǒng)的磁盤存儲空間,并最終影響服務(wù)的運行。

        「清理工具」

        ?

        Corntab

        ?

        首先,我們介紹的是 Linux corntab ,它是 Linux 系統(tǒng)下的軟件,可以自動地按照我們設(shè)定的時間,周期性地執(zhí)行我們編寫的相關(guān)腳本。

        crontab 定時腳本的方式相對靈活,可以按照我們的業(yè)務(wù)需求來設(shè)置處理日志的維護方式,比如這里我們希望定期清除 ZooKeeper 服務(wù)運行的日志,而不想清除數(shù)據(jù)快照的文件,則可以通過腳本設(shè)置,達到只對數(shù)據(jù)日志文件進行清理的目的。

        ?

        PurgeTxnLog

        ?

        ZooKeeper 自身還提供了 PurgeTxnLog 工具類,用來清理 snapshot 數(shù)據(jù)快照文件和系統(tǒng)日志。

        PurgeTxnLog 清理方式和我們上面介紹的方式十分相似,也是通過定時腳本執(zhí)行任務(wù),唯一的不同是,上面提到在編寫日志清除 logsCleanWeek 的時候 ,我們使用的是原生 shell 腳本自己手動編寫的數(shù)據(jù)日志清理邏輯,而使用 PurgeTxnLog 則可以在編寫清除腳本的時候調(diào)用 ZooKeeper 為我們提供的工具類完成日志清理工作。

        如下面的代碼所示,首先,我們在/usr/bin目錄下創(chuàng)建一個 PurgeLogsClean 腳本。注意這里的腳本也是一個 shell 文件。

        在腳本中我們只需要編寫 PurgeTxnLog 類的調(diào)用程序,系統(tǒng)就會自動通過 PurgeTxnLog 工具類為我們完成對應(yīng)日志文件的清理工作。

        #!/bin/sh??
        java?-cp?"$CLASSPATH"?org.apache.zookeeper.server.PurgeTxnLog?
        echo?"清理完成"?

        PurgeTxnLog 方式與 crontab 相比,使用起來更加容易而且也更加穩(wěn)定安全,不過 crontab 方式更加靈活,我們可以根據(jù)不同的業(yè)務(wù)需求編寫自己的清理邏輯。

        實現(xiàn)分布式鎖

        分布式鎖的目的是保證在分布式部署的應(yīng)用集群中,多個服務(wù)在請求同一個方法或者同一個業(yè)務(wù)操作的情況下,對應(yīng)業(yè)務(wù)邏輯只能被一臺機器上的一個線程執(zhí)行,避免出現(xiàn)并發(fā)問題。

        ?

        實現(xiàn)分布式鎖目前有三種流行方案,即基于數(shù)據(jù)庫、Redis、ZooKeeper 的方案

        ?

        「方案一:」

        使用節(jié)點中的存儲數(shù)據(jù)區(qū)域,ZK中節(jié)點存儲數(shù)據(jù)的大小不能超過1M,但是只是存放一個標識是足夠的,線程獲得鎖時,先檢查該標識是否是無鎖標識,若是可修改為占用標識,使用完再恢復(fù)為無鎖標識

        「方案二:」

        使用子節(jié)點,每當有線程來請求鎖的時候,便在鎖的節(jié)點下創(chuàng)建一個子節(jié)點,子節(jié)點類型必須維護一個順序,對子節(jié)點的自增序號進行排序,默認總是最小的子節(jié)點對應(yīng)的線程獲得鎖,釋放鎖時刪除對應(yīng)子節(jié)點便可

        347aabf72f527ca1a1d64e4c07f6df65.webp

        「死鎖風(fēng)險:」

        兩種方案其實都是可行的,但是使用鎖的時候一定要去規(guī)避死鎖

        • 方案一看上去是沒問題的,用的時候設(shè)置標識,用完清除標識,但是要是持有鎖的線程發(fā)生了意外,釋放鎖的代碼無法執(zhí)行,鎖就無法釋放,其他線程就會一直等待鎖,相關(guān)同步代碼便無法執(zhí)行

        • 方案二也存在這個問題,但方案二可以利用ZK的臨時順序節(jié)點來解決這個問題,只要線程發(fā)生了異常導(dǎo)致程序中斷,就會丟失與ZK的連接,ZK檢測到該鏈接斷開,就會自動刪除該鏈接創(chuàng)建的臨時節(jié)點,這樣就可以達到即使占用鎖的線程程序發(fā)生意外,也能保證鎖正常釋放的目的

        「避免羊群效應(yīng)」

        把鎖請求者按照后綴數(shù)字進行排隊,后綴數(shù)字小的鎖請求者先獲取鎖。

        如果所有的鎖請求者都 watch 鎖持有者,當代表鎖請求者的 znode 被刪除以后,所有的鎖請求者都會通知到,但是只有一個鎖請求者能拿到鎖。這就是羊群效應(yīng)。

        ?

        為了避免羊群效應(yīng),每個鎖請求者 watch 它前面的鎖請求者。

        ?

        每次鎖被釋放,只會有一個鎖請求者 會被通知到。

        這樣做還讓鎖的分配具有公平性,鎖定的分配遵循先到先得的原則。

        02d56955ee64040863c6c014499c046e.webp

        「用 ZooKeeper 實現(xiàn)分布式鎖的算法流程,根節(jié)點為 /lock:」

        • 客戶端連接 ZooKeeper,并在/lock下創(chuàng)建臨時有序子節(jié)點,第一個客戶端對應(yīng)的子節(jié)點為/lock/lock01/00000001,第二個為 /lock/lock01/00000002;

        • 其他客戶端獲取/lock01下的子節(jié)點列表,判斷自己創(chuàng)建的子節(jié)點是否為當前列表中序號最小的子節(jié)點;

        • 如果是則認為獲得鎖,執(zhí)行業(yè)務(wù)代碼,否則通過 watch 事件監(jiān)聽/lock01的子節(jié)點變更消息,獲得變更通知后重復(fù)此步驟直至獲得鎖;

        • 完成業(yè)務(wù)流程后,刪除對應(yīng)的子節(jié)點,釋放分布式鎖;

        在實際開發(fā)中,可以應(yīng)用 Apache Curator 來快速實現(xiàn)分布式鎖,Curator 是 Netflix 公司開源的一個 ZooKeeper 客戶端,對 ZooKeeper 原生 API 做了抽象和封裝。

        實現(xiàn)分布式ID

        我們可以通過 ZooKeeper 自身的客戶端和服務(wù)器運行模式,來實現(xiàn)一個分布式網(wǎng)絡(luò)環(huán)境下的 ID 請求和分發(fā)過程。

        ?

        每個需要 ID 編碼的業(yè)務(wù)服務(wù)器可以看作是 ZooKeeper 的客戶端。ID 編碼生成器可以作為 ZooKeeper 的服務(wù)端。

        ?

        客戶端通過發(fā)送請求到 ZooKeeper 服務(wù)器,來獲取編碼信息,服務(wù)端接收到請求后,發(fā)送 ID 編碼給客戶端。

        「實現(xiàn)原理:」

        可以利用 ZooKeeper 數(shù)據(jù)模型中的順序節(jié)點作為 ID 編碼。

        • 客戶端通過調(diào)用 create 函數(shù)創(chuàng)建順序節(jié)點。服務(wù)器成功創(chuàng)建節(jié)點后,會響應(yīng)客戶端請求,把創(chuàng)建好的節(jié)點信息發(fā)送給客戶端。

        • 客戶端用數(shù)據(jù)節(jié)點名稱作為 ID 編碼,進行之后的本地業(yè)務(wù)操作。

        利用 ZooKeeper 中的順序節(jié)點特性,很容易使我們創(chuàng)建的 ID 編碼具有有序的特性。并且我們也可以通過客戶端傳遞節(jié)點的名稱,根據(jù)不同的業(yè)務(wù)編碼區(qū)分不同的業(yè)務(wù)系統(tǒng),從而使編碼的擴展能力更強。

        ?

        雖然使用 ZooKeeper 的實現(xiàn)方式有這么多優(yōu)點,但也會有一些潛在的問題。

        ?

        其中最主要的是,在定義編碼的規(guī)則上還是強烈依賴于程序員自身的能力和對業(yè)務(wù)的深入理解。

        很容易出現(xiàn)因為考慮不周,造成設(shè)置的規(guī)則在運行一段時間后,無法滿足業(yè)務(wù)要求或者安全性不夠等問題。

        實現(xiàn)負載均衡

        「常見負載均衡算法」

        ?

        輪詢法

        ?

        輪詢法是最為簡單的負載均衡算法,當接收到來自網(wǎng)絡(luò)中的客戶端請求后,負載均衡服務(wù)器會按順序逐個分配給后端服務(wù)。

        比如集群中有 3 臺服務(wù)器,分別是 server1、server2、server3,輪詢法會按照 sever1、server2、server3 這個順序依次分發(fā)會話請求給每個服務(wù)器。當?shù)谝淮屋喸兘Y(jié)束后,會重新開始下一輪的循環(huán)。

        ?

        隨機法

        ?

        隨機算法是指負載均衡服務(wù)器在接收到來自客戶端的請求后,會根據(jù)一定的隨機算法選中后臺集群中的一臺服務(wù)器來處理這次會話請求。

        不過,當集群中備選機器變的越來越多時,通過統(tǒng)計學(xué)我們可以知道每臺機器被抽中的概率基本相等,因此隨機算法的實際效果越來越趨近輪詢算法。

        ?

        原地址哈希法

        ?

        原地址哈希算法的核心思想是根據(jù)客戶端的 IP 地址進行哈希計算,用計算結(jié)果進行取模后,根據(jù)最終結(jié)果選擇服務(wù)器地址列表中的一臺機器,處理該條會話請求。

        采用這種算法后,當同一 IP 的客戶端再次訪問服務(wù)端后,負載均衡服務(wù)器最終選舉的還是上次處理該臺機器會話請求的服務(wù)器,也就是每次都會分配同一臺服務(wù)器給客戶端。

        ?

        加權(quán)輪詢法

        ?

        加權(quán)輪詢的方式與輪詢算法的方式很相似,唯一的不同在于選擇機器的時候,不只是單純按照順序的方式選擇,還根據(jù)機器的配置和性能高低有所側(cè)重,配置性能好的機器往往首先分配。

        ?

        加權(quán)隨機法

        ?

        加權(quán)隨機法和我們上面提到的隨機算法一樣,在采用隨機算法選舉服務(wù)器的時候,會考慮系統(tǒng)性能作為權(quán)值條件。

        ?

        最小連接數(shù)法

        ?

        最小連接數(shù)算法是指,根據(jù)后臺處理客戶端的連接會話條數(shù),計算應(yīng)該把新會話分配給哪一臺服務(wù)器。

        一般認為,連接數(shù)越少的機器,在網(wǎng)絡(luò)帶寬和計算性能上都有很大優(yōu)勢,會作為最優(yōu)先分配的對象。

        「利用 ZooKeeper 實現(xiàn) 負載均衡 算法」

        ?

        這里我們通過采用最小連接數(shù)算法,來確定究竟如何均衡地分配網(wǎng)絡(luò)會話請求給后臺客戶端。

        ?

        如下圖所示,建立的 ZooKeeper 數(shù)據(jù)模型中 Severs 節(jié)點可以作為存儲服務(wù)器列表的父節(jié)點。

        在它下面創(chuàng)建 servers_host1、servers_host2、servers_host3等臨時節(jié)點來存儲集群中的服務(wù)器運行狀態(tài)信息。

        bfeaf4bd36c3362ebe90842258300839.webp

        整個實現(xiàn)的過程如下圖所示。

        7f843746e6214fea2576942276503a91.webp
        • 首先,在接收到客戶端的請求后,通過 getData 方法獲取服務(wù)端 Severs 節(jié)點下的服務(wù)器列表,其中每個節(jié)點信息都存儲有當前服務(wù)器的連接數(shù)。

        • 通過判斷選擇最少的連接數(shù)作為當前會話的處理服務(wù)器,并通過 setData 方法將該節(jié)點連接數(shù)加 1。

        • 最后,當客戶端執(zhí)行完畢,再調(diào)用 setData 方法將該節(jié)點信息減 1。

        • 我們定義當服務(wù)器接收到會話請求后。在 ZooKeeper 服務(wù)端增加連接數(shù)的 addBlance 方法。

        • 我們通過 readData 方法獲取服務(wù)器最新的連接數(shù),之后將該連接數(shù)加 1,再通過 writeData 方法將新的連接數(shù)信息寫入到服務(wù)端對應(yīng)節(jié)點信息中。

        • 當服務(wù)器處理完該會話請求后,需要更新服務(wù)端相關(guān)節(jié)點的連接數(shù)。

        • 具體的操作與 addBlance 方法基本一樣,只是對獲取的連接信息進行減一操作。

        「這里注意:」

        我們?nèi)粘S玫降呢撦d均衡器主要是選擇后臺處理的服務(wù)器,并給其分發(fā)請求。

        ?

        而通過 ZooKeeper 實現(xiàn)的服務(wù)器,只提供了服務(wù)器的篩選工作。

        ?

        在請求分發(fā)的過程中,還是通過負載算法計算出要訪問的服務(wù)器,之后客戶端自己連接該服務(wù)器,完成請求操作。

        開源框架使用案例

        「Dubbo與ZooKeeper」

        Dubbo 是阿里巴巴開發(fā)的一套開源的技術(shù)框架,是一款高性能、輕量級的開源 Java RPC 框架。

        「用ZooKeeper做注冊中心」

        在整個 Dubbo 框架的實現(xiàn)過程中,注冊中心是其中最為關(guān)鍵的一點,它保證了整個 PRC 過程中服務(wù)對外的透明性。

        而 Dubbo 的注冊中心也是通過 ZooKeeper 來實現(xiàn)的。

        如下圖所示,在整個 Dubbo 服務(wù)的啟動過程中,服務(wù)提供者會在啟動時向 /dubbo/com.foo.BarService/providers目錄寫入自己的 URL 地址,這個操作可以看作是一個 ZooKeeper 客戶端在 ZooKeeper 服務(wù)器的數(shù)據(jù)模型上創(chuàng)建一個數(shù)據(jù)節(jié)點。

        服務(wù)消費者在啟動時訂閱 /dubbo/com.foo.BarService/providers 目錄下的提供者 URL 地址,并向 /dubbo/com.foo.BarService/consumers 目錄寫入自己的 URL 地址。

        該操作是通過 ZooKeeper 服務(wù)器在 /consumers 節(jié)點路徑下創(chuàng)建一個子數(shù)據(jù)節(jié)點,然后再在請求會話中發(fā)起對 /providers 節(jié)點的 watch 監(jiān)控

        ebae44b9120e26867e442a197fd20dd8.webp

        「Kafka與ZooKeeper」

        「Zookeeper的作用」

        由于 Broker 服務(wù)器采用分布式集群的方式工作,那么在服務(wù)的運行過程中,難免出現(xiàn)某臺機器因異常而關(guān)閉的狀況。

        為了保證整個 Kafka 集群的可用性,需要在系統(tǒng)中監(jiān)控整個機器的運行情況。而 Kafka 可以通過 ZooKeeper 中的數(shù)據(jù)節(jié)點,將網(wǎng)絡(luò)中機器的運行統(tǒng)計存儲在數(shù)據(jù)模型中的 brokers 節(jié)點下。

        在 Kafka 的 Topic 信息注冊中也需要使用到 ZooKeeper ,在 Kafka 中同一個Topic 消息容器可以分成多個不同片,而這些分區(qū)既可以存在于一臺 Broker 服務(wù)器中,也可以存在于不同的 Broker 服務(wù)器中。

        而在 Kafka 集群中,每臺 Broker 服務(wù)器又相對獨立。

        為了能夠讀取這些以分布式方式存儲的分區(qū)信息,Kafka 會將這些分區(qū)信息在 Broker 服務(wù)器中的對應(yīng)關(guān)系存儲在 ZooKeeper 數(shù)據(jù)模型的 topic 節(jié)點上,每一個 topic 在 ZooKeeper 數(shù)據(jù)節(jié)點上都會以 /brokers/topics/[topic] 的形式存在。

        614bc5e0b8d186cb0704b23c57934f77.webp參考資料

        《從Paxos到Zookeeper 分布式一致性原理與實踐》

        瀏覽 16
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

          <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            操碰在线观看视频 | 一级免费Aa片 | 91超碰人人 | 国产做19a爰片久久毛片A片 | 国精产品一区二区三区mba | 成人片免费观看在线毛片 | 曰批全过程120分钟视频 | 久久午夜免费观看 | 亚洲高清视屏 | 又粗又长又硬呜呜呜呜 |