走進Zookeeper,剖析內部構造

 

文章目錄

 

1、前言 2、分佈式存在問題 + zookeeper三個功能 + zookeeper結構 + zookeeper四大功能

第一,zookeeper的引入,分佈式架構存在的問題:使用分佈式系統就沒法避免對節點管理的問題(須要實時感知節點的狀態、對節點進行統一管理等等),因爲這些問題處理起來可能相對麻煩和提升了系統的複雜性,ZooKeeper做爲一個可以通用解決這些問題的中間件就應運而生了。node

第二,開發中用到zookeeper的三個地方(kafka 註冊中心 分佈式鎖)
一、Kafka:Kafka使用ZooKeeper進行分佈式部署的broker(每一臺kafka就是一個broker)的管理,Kafka使用ZooKeeper管理本身的元數據配置。
二、註冊中心:和Eureka同樣,能夠做爲註冊中心、配置中心。
三、分佈式鎖:ZooKeeper能夠做爲分佈式鎖的一種實現。mysql

第三,zookeeper結構:樹型數據結構,ZNode四種類型節點 + 監聽器
第四,zookeeper四個功能(兩種結構實現):統一配置管理、統一命名服務、分佈式鎖、集羣管理面試

3、Zookeeper結構:ZNode + 監聽器

3.1 ZNode

ZooKeeper的數據結構,跟Unix文件系統很是相似,能夠看作是一顆樹,每一個節點叫作ZNode。每個節點能夠經過路徑來標識,結構圖以下:redis

在這裏插入圖片描述

那ZooKeeper這顆"樹"有什麼特色呢??
ZooKeeper的節點咱們稱之爲Znode,Znode分爲兩種類型:
短暫/臨時(Ephemeral):當客戶端和服務端斷開鏈接後,所建立的Znode(節點)會自動刪除
持久(Persistent):當客戶端和服務端斷開鏈接後,所建立的Znode(節點)不會刪除sql

ZooKeeper和Redis同樣,也是C/S結構(分紅客戶端和服務端)數據庫

3.2 監聽器

在上面咱們已經簡單知道了ZooKeeper的數據結構了,ZooKeeper的樹形數據結構須要配合監聽器才能完成四個功能。常見的監聽場景有如下兩項:編程

監聽Znode節點的數據變化
監聽子節點的增減變化後端

在這裏插入圖片描述

小結:經過監聽+Znode節點(持久/短暫[臨時]),ZooKeeper就能夠完成四個功能。bash

3、ZooKeeper四個功能(統一配置管理、統一命名服務、分佈式鎖、集羣管理)

3.1 統一配置管理:永久節點

3.1.1 理論:zookeeper實現統一配置

問題:好比咱們如今有三個系統A、B、C,他們有三份配置,分別是ASystem.yml、BSystem.yml、CSystem.yml,而後,這三份配置又很是相似,不少的配置項幾乎都同樣。
此時,若是咱們要改變其中一份配置項的信息,極可能其餘兩份都要改。而且,改變了配置項的信息極可能就要重啓系統網絡

理論指望:咱們但願把ASystem.yml、BSystem.yml、CSystem.yml相同的配置項抽取出來成一份公用的配置common.yml,而且即使common.yml改了,也不須要系統A、B、C重啓。
在這裏插入圖片描述

實際作法:咱們能夠將common.yml這份配置放在ZooKeeper的Znode節點中,系統A、B、C監聽着這個Znode節點有無變動,若是變動了,及時響應。
在這裏插入圖片描述
對於上圖的解釋:
zookeeper中根節點爲 「/」 ,而後下面一個 「/configuration」 節點,我麼講application-common.properties,即配置文件的公共部分放在這個節點上,而後全部使用到這個application-common.properties做爲公共配置的SOA服務,監聽這個節點的數據變化就好,zk.subscribeDataChanges訂閱, handleDataChange監聽節點的數據變化,zookeeper節點中數據變化時響應;handleDataDeleted監聽節點的刪除,zookeeper節點被刪除響應。

3.1.2 實踐:zookeeper實現統一配置

3.1.2.1 分佈式部署催生統一配置 + 理論上如何實現統一配置 + 實踐上zookeeper實現統一配置

問題:統一配置存在的意義?爲何要用統一配置?
回答:後端使用微服務開發,分佈式部署,分佈式部署不可能一個個修改配置文件application.properties/application.yaml
。咱們作項目時用到的配置好比數據庫配置等…咱們都是寫死在項目裏面,若是須要更改,那麼也是的修改配置文件而後再投產上去,那麼問題來了,若是作集羣的呢,有100臺機器,這時候作修改那就太不切實際了;那麼就須要用到統一配置管理啦。

問題2:理論上,如何實現統一配置?
解決思路

1.把公共配置抽取出來
2.對公共配置進行維護
3.修改公共配置後應用不須要從新部署

問題3:實踐上,統一配置的具體方案(採用zookeeper實現統一配置)?
回答
步驟1:公共配置抽取存放於zookeeper中並落地數據庫( 下面代碼:第一個main,前半部分
步驟2:對公共配置修改後發佈到zookeeper中並落地數據庫(下面代碼:第一個main,後半部分
步驟3:對應用開啓配置實時監聽,zookeeper配置文件一旦被修改,應用可實時監聽到並獲取(下面代碼:第二個main
如圖:
在這裏插入圖片描述

3.1.2.2 代碼:zookeeper實現統一配置

3.1.2.2.1 Config:一個傳輸的Bean對象
public class Config implements Serializable{  // 實現了Serializable接口,就必定涉及網絡傳輸和磁盤讀寫   僅僅一個bean 好懂

    private static final long serialVersionUID = 1L;  // 顯式指定版本號和隱式默認版本號
    private String userNm;
    private String userPw;

    public Config() {
    }
    public Config(String userNm, String userPw) {
        this.userNm = userNm;
        this.userPw = userPw;
    }
    public String getUserNm() {
        return userNm;
    }
    public void setUserNm(String userNm) {
        this.userNm = userNm;
    }
    public String getUserPw() {
        return userPw;
    }
    public void setUserPw(String userPw) {
        this.userPw = userPw;
    }
    @Override
    public String toString() {
        return "Config [userNm=" + userNm + ", userPw=" + userPw + "]";
    }

}
3.1.2.2.2 ZkConfigMag:提供三個工具方法,讀庫 寫庫 寫zk
public class ZkConfigMag {   // 提供三個工具方法,讀庫 寫庫  寫zk

    private Config config;
    /**
     * 從數據庫加載配置
     */
    public Config downLoadConfigFromDB(){
        //getDB  這裏省略了數據庫操做
        config = new Config("nm", "pw");   // 建立一個config對象
        return config;
    }

    /**
     * 配置文件上傳到數據庫  這裏省略了  good
     */
    public void upLoadConfigToDB(String nm, String pw){
        if(config==null)config = new Config();
        config.setUserNm(nm);
        config.setUserPw(pw);
        //updateDB   配置文件上傳到數據庫,這裏省略了數據庫操做
    }

    /**
     * 配置文件同步到zookeeper   good
     */
    public void syncConfigToZk(){
        ZkClient zk = new ZkClient("localhost:2181");   // 鏈接zk
        if(!zk.exists("/zkConfig")){
            zk.createPersistent("/zkConfig",true);   // 不存在就建立一個持久化的節點
        }
        zk.writeData("/zkConfig", config);  // 寫數據,將config對象寫入到zk裏面去,難怪Config類,要實現 可序列化 接口
        zk.close();
    }
}
3.1.2.2.3 ZkConfigTest:第一個main,修改zookeeper配置
public class ZkConfigTest {   // 第一,修改

    public static void main(String[] args) {
        ZkConfigMag mag = new ZkConfigMag();   // 新建一個ZkConfigMag 對象
        Config config = mag.downLoadConfigFromDB();  // 讀庫  設置局部變量config
        System.out.println("....加載數據庫配置...."+config.toString());   //打印下從數據庫中讀出的config
        mag.syncConfigToZk();    // 將config寫入到zk  讀庫會設置config
        System.out.println("....同步配置文件到zookeeper....");  // 成功寫zk

        //歇會,這樣看比較清晰
        try {
            Thread.sleep( 10000);   // 給看清楚,10s
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        mag.upLoadConfigToDB("cwhcc", "passwordcc");   // 寫數據庫
        System.out.println("....修改配置文件...."+config.toString());
        mag.syncConfigToZk();   // 寫zk
        System.out.println("....同步配置文件到zookeeper....");
        
    }

}
3.1.2.2.4 ZkGetConfigClient:第二個main,監聽zookeeper修改
public class ZkGetConfigClient {   // 第二,監聽zookeeper

    private Config config;

    public Config getConfig() {
        ZkClient zk = new ZkClient("localhost:2181");    // 鏈接zk
        config = (Config)zk.readData("/zkConfig");   // 讀取zk,設置變量config
        System.out.println("加載到配置:"+config.toString());   // 打印下

        //監聽配置文件修改
        zk.subscribeDataChanges("/zkConfig", new IZkDataListener(){
            // 監聽localhost:2181的zkConfig節點,  一旦監聽到,調用方法 handleDataChange handleDataDeleted
            @Override
            public void handleDataChange(String arg0, Object arg1)
                    throws Exception {
                config = (Config) arg1;
                System.out.println("監聽到配置文件被修改:"+config.toString());   // config修改,監聽打印
            }

            @Override
            public void handleDataDeleted(String arg0) throws Exception {
                config = null;
                System.out.println("監聽到配置文件被刪除");  // config刪除,監聽打印
            }

        });
        return config;
    }
    public static void main(String[] args) {
        ZkGetConfigClient client = new ZkGetConfigClient();  // 建立一個當前類對象
        client.getConfig();    // 當前類對象.getConfig()
        System.out.println(client.config.toString()); // 打印當前類對象的config
        for(int i = 0;i<10;i++){            // 遍歷10次
            System.out.println(client.config.toString());   // 打印當前類對象的config
            try {
                Thread.sleep(1000);   // 每次休息1s
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }


}
3.1.2.2.5 輸出結果:第一個main,修改zookeeper配置;第二個main,監聽zookeeper配置的修改

第一個main,修改zookeeper配置
在這裏插入圖片描述

第二個main,監聽zookeeper配置的修改

在這裏插入圖片描述

3.2 統一命名服務:永久節點

統一命名服務定義:相似域名,就是咱們爲zookeeper某一部分的資源給它取一個名字,別人經過這個名字就能夠拿到對應的資源。
域名的使用:如今我有一個域名www.csdn.com,但我這個域名下有多臺機器(一個局域網ip對應一個機器):
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
別人是經過www.csdn.com訪問到個人機器,而不是經過IP去訪問。
統一命名服務的使用:如今zookeeper集羣中有一個命名服務 /myService,但這個命名服務下有多臺機器(一個局域網ip對應一個機器):
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
別人訪問 zookeeper節點/myService 便可訪問到個人機器,而不是經過IP去訪問。如圖:
在這裏插入圖片描述

3.3 分佈式鎖:臨時順序節點

金手指:從鎖到分佈式鎖
分佈式鎖文章連接
分佈式鎖和進程內的鎖本質上是同樣的。
一、要互斥,同一時刻只能被一臺機器上的一個線程得到。
二、最好支持阻塞,而後喚醒,這樣那些等待的線程不用循環重試。
三、最好能夠重入(本文沒有涉及,參見《編程世界的那把鎖》)
四、得到鎖和釋放鎖速度要快
五、對於分佈式鎖,須要找到一個集中的「地方」(數據庫,Redis, Zookeeper等)來保存鎖,這個地方最好是高可用的。
六、考慮到「不可靠的」分佈式環境, 分佈式鎖須要設定過時時間
七、CAS的思想很重要。

問題:ZooKeeper如何實現分佈式鎖?
標準答案:使用指定節點名,zookeeper節點的惟一性來實現分佈式鎖的互斥

下面來看看:系統A、B、C都去訪問/locks節點
在這裏插入圖片描述
訪問的時候會建立帶順序號的臨時/短暫(EPHEMERAL_SEQUENTIAL)節點,好比,系統A建立了id_000000節點,系統B建立了id_000002節點,系統C建立了id_000001節點。
在這裏插入圖片描述
分佈式鎖理論規則
拿到/locks節點下的全部子節點(id_000000,id_000001,id_000002),判斷本身建立的是否是最小的那個節點
(1)若是是,則拿到鎖執行。而後,執行完操做後,把建立的節點給刪掉
(2)若是不是,則監聽比本身要小1的節點變化
分佈式鎖實踐流程
(1)系統A拿到/locks節點下的全部子節點,通過比較,發現本身(id_000000),是全部子節點最小的,因此獲得鎖;
(2)系統B拿到/locks節點下的全部子節點,通過比較,發現本身(id_000002),不是全部子節點最小的。因此監聽比本身小1的節點id_000001的狀態;
(3)系統C拿到/locks節點下的全部子節點,通過比較,發現本身(id_000001),不是全部子節點最小的。因此監聽比本身小1的節點id_000000的狀態;
(4)等到系統A執行完操做之後,將本身建立的節點刪除(id_000000)。經過監聽,系統C發現id_000000節點已經刪除了,發現本身已是最小的節點了,因而順利拿到鎖;
(5)系統C執行完以後,釋放鎖,系統B成爲最小節點,加鎖執行,執行完釋放鎖。

3.4 集羣狀態:臨時順序節點(監聽節點 + 動態選主)

集羣狀態1:使用zookeeper監聽集羣中其餘節點狀態(臨時節點)
以三個系統A、B、C爲例,在ZooKeeper中建立臨時節點便可:
在這裏插入圖片描述
只要系統A掛了,那/groupMember/A這個節點就會刪除,經過監聽groupMember下的子節點,系統B和C就可以感知到系統A已經掛了。(新增也是同理)
集羣狀態2:動態選主(臨時順序節點)
除了可以感知節點的上下線變化,ZooKeeper還能夠實現動態選舉Master的功能。(若是集羣是主從架構模式下)
可是注意,若是想要實現動態選舉Master的功能,Znode節點的類型要求是帶順序號的臨時節點(EPHEMERAL_SEQUENTIAL)。選主階段,Zookeeper會每次選舉最小編號的做爲Master,若是Master掛了,天然對應的Znode節點就會刪除。而後讓新的最小編號做爲Master,這樣就能夠實現動態選舉的功能了。

4、面試金手指

第一,zookeeper的引入,分佈式架構存在的問題:使用分佈式系統就沒法避免對節點管理的問題(須要實時感知節點的狀態、對節點進行統一管理等等),因爲這些問題處理起來可能相對麻煩和提升了系統的複雜性,ZooKeeper做爲一個可以通用解決這些問題的中間件就應運而生了。

第二,開發中用到zookeeper的三個地方(kafka 註冊中心 分佈式鎖)
一、Kafka:Kafka使用ZooKeeper進行分佈式部署的broker(每一臺kafka就是一個broker)的管理,Kafka使用ZooKeeper管理本身的元數據配置。
二、註冊中心:和Eureka同樣,能夠做爲註冊中心、配置中心。
三、分佈式鎖:ZooKeeper能夠做爲分佈式鎖的一種實現。

第三,zookeeper結構:樹型數據結構,ZNode四種類型節點 + 監聽器
第四,zookeeper四個功能(兩種結構實現):統一配置管理、統一命名服務、分佈式鎖、集羣管理

4.1 zookeeper兩個結構:ZNode + 監聽器

ZNode:ZooKeeper這顆"樹"有什麼特色呢??
ZooKeeper的節點咱們稱之爲Znode,Znode分爲兩種類型:
短暫/臨時(Ephemeral):當客戶端和服務端斷開鏈接後,所建立的Znode(節點)會自動刪除
持久(Persistent):當客戶端和服務端斷開鏈接後,所建立的Znode(節點)不會刪除

ZooKeeper和Redis同樣,也是C/S結構(分紅客戶端和服務端)

監聽器:ZooKeeper的樹形數據結構須要配合監聽器才能完成四個功能。常見的監聽場景有如下兩項:
(1)監聽Znode節點的數據變化
(2)監聽子節點的增減變化

4.2 zookeeper四個功能:統一配置管理 + 統一命名服務 + 分佈式鎖 + 集羣管理

4.2.1 zookeeper統一配置管理:永久節點

問題:好比咱們如今有三個系統A、B、C,他們有三份配置,分別是ASystem.yml、BSystem.yml、CSystem.yml,而後,這三份配置又很是相似,不少的配置項幾乎都同樣。
此時,若是咱們要改變其中一份配置項的信息,極可能其餘兩份都要改。而且,改變了配置項的信息極可能就要重啓系統

理論指望:咱們但願把ASystem.yml、BSystem.yml、CSystem.yml相同的配置項抽取出來成一份公用的配置common.yml,而且即使common.yml改了,也不須要系統A、B、C重啓。
實際作法:咱們能夠將common.yml這份配置放在ZooKeeper的Znode節點中,系統A、B、C監聽着這個Znode節點有無變動,若是變動了,及時響應。
zookeeper中根節點爲 「/」 ,而後下面一個 「/configuration」 節點,我麼講application-common.properties,即配置文件的公共部分放在這個節點上,而後全部使用到這個application-common.properties做爲公共配置的SOA服務,監聽這個節點的數據變化就好,zk.subscribeDataChanges訂閱, handleDataChange監聽節點的數據變化,zookeeper節點中數據變化時響應;handleDataDeleted監聽節點的刪除,zookeeper節點被刪除響應。

問題:統一配置存在的意義?爲何要用統一配置?
回答:後端使用微服務開發,分佈式部署,分佈式部署不可能一個個修改配置文件application.properties/application.yaml
。咱們作項目時用到的配置好比數據庫配置等…咱們都是寫死在項目裏面,若是須要更改,那麼也是的修改配置文件而後再投產上去,那麼問題來了,若是作集羣的呢,有100臺機器,這時候作修改那就太不切實際了;那麼就須要用到統一配置管理啦。
問題2:理論上,如何實現統一配置?
解決思路

1.把公共配置抽取出來
2.對公共配置進行維護
3.修改公共配置後應用不須要從新部署
問題3:實踐上,統一配置的具體方案(採用zookeeper實現統一配置)?
回答
步驟1:公共配置抽取存放於zookeeper中並落地數據庫( 下面代碼:第一個main,前半部分
步驟2:對公共配置修改後發佈到zookeeper中並落地數據庫(下面代碼:第一個main,後半部分
步驟3:對應用開啓配置實時監聽,zookeeper配置文件一旦被修改,應用可實時監聽到並獲取(下面代碼:第二個main

4.2.2 zookeeper實現統一命名服務:永久節點

統一命名服務定義:相似域名,就是咱們爲zookeeper某一部分的資源給它取一個名字,別人經過這個名字就能夠拿到對應的資源。
域名的使用:如今我有一個域名www.csdn.com,但我這個域名下有多臺機器(一個局域網ip對應一個機器):
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
別人訪問www.csdn.com便可訪問到個人機器,而不是經過IP去訪問。
統一命名服務的使用:如今zookeeper集羣中有一個命名服務 /myService,但這個命名服務下有多臺機器(一個局域網ip對應一個機器):
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
別人訪問 zookeeper節點/myService 便可訪問到個人機器,而不是經過IP去訪問。

4.2.3 zookeeper實現分佈式鎖:臨時順序節點

金手指:從鎖到分佈式鎖
分佈式鎖文章連接
分佈式鎖和進程內的鎖本質上是同樣的。
一、要互斥,同一時刻只能被一臺機器上的一個線程得到。
二、最好支持阻塞,而後喚醒,這樣那些等待的線程不用循環重試。
三、最好能夠重入(本文沒有涉及,參見《編程世界的那把鎖》)
四、得到鎖和釋放鎖速度要快
五、對於分佈式鎖,須要找到一個集中的「地方」(數據庫,Redis, Zookeeper等)來保存鎖,這個地方最好是高可用的。
六、考慮到「不可靠的」分佈式環境, 分佈式鎖須要設定過時時間
七、CAS的思想很重要。

問題:ZooKeeper如何實現分佈式鎖?
標準答案:使用指定節點名,zookeeper節點的惟一性來實現分佈式鎖的互斥
下面來看看:系統A、B、C都去訪問/locks節點,訪問的時候會建立帶順序號的臨時/短暫(EPHEMERAL_SEQUENTIAL)節點,好比,系統A建立了id_000000節點,系統B建立了id_000002節點,系統C建立了id_000001節點。
分佈式鎖理論規則
拿到/locks節點下的全部子節點(id_000000,id_000001,id_000002),判斷本身建立的是否是最小的那個節點
(1)若是是,則拿到鎖。而後,執行完操做後,把建立的節點給刪掉
(2)若是不是,則監聽比本身要小1的節點變化
分佈式鎖實踐流程
(1)系統A拿到/locks節點下的全部子節點,通過比較,發現本身(id_000000),是全部子節點最小的,因此獲得鎖;
(2)系統B拿到/locks節點下的全部子節點,通過比較,發現本身(id_000002),不是全部子節點最小的。因此監聽比本身小1的節點id_000001的狀態;
(3)系統C拿到/locks節點下的全部子節點,通過比較,發現本身(id_000001),不是全部子節點最小的。因此監聽比本身小1的節點id_000000的狀態;
(4)等到系統A執行完操做之後,將本身建立的節點刪除(id_000000)。經過監聽,系統C發現id_000000節點已經刪除了,發現本身已是最小的節點了,因而順利拿到鎖;
(5)系統C執行完以後,釋放鎖,系統B成爲最小節點,加鎖執行,執行完釋放鎖。

4.2.4 zookeeper實現集羣管理:臨時節點/臨時順序節點

集羣狀態1:使用zookeeper監聽集羣中其餘節點狀態(臨時節點+監聽器節點刪除)
以三個系統A、B、C爲例,在ZooKeeper中建立臨時節點便可:只要系統A掛了,那/groupMember/A這個節點就會刪除,經過監聽groupMember下的子節點,系統B和C就可以感知到系統A已經掛了。(新增也是同理)
集羣狀態2:動態選主(臨時順序節點+監聽器節點刪除)
除了可以感知節點的上下線變化,ZooKeeper還能夠實現動態選舉Master的功能。(若是集羣是主從架構模式下)
可是注意,若是想要實現動態選舉Master的功能,Znode節點的類型要求是帶順序號的臨時節點(EPHEMERAL_SEQUENTIAL)。選主階段,Zookeeper會每次選舉最小編號的做爲Master,若是Master掛了,天然對應的Znode節點就會刪除。而後讓新的最小編號做爲Master,這樣就能夠實現動態選舉的功能了。

4.2.5 小結四個功能如何用兩個結構來實現

統一配置功能(永久節點+監聽器節點數據修改):
(1)節點四種類型,要使用永久節點,不能一個客戶端斷開鏈接就刪除節點;
(2)要使用監聽器(兩個功能中的數據修改功能),application-common.properties配置改變,客戶端要能夠監聽到;
(3)實踐:此功能eureka的註冊中心

統一命名服務(永久節點):
(1)使用統一命名 /myService,相似於域名,固然要使用永久節點。

第三,分佈式鎖(臨時順序節點+監聽器節點刪除
(1)使用節點:指定節點名具備惟一性,建立節點就是獲取鎖,實現互斥,finally中刪除節點就是釋放鎖,別的SOA客戶端服務能夠來建立這個節點名的節點了,再次開始競爭;
(2)使用臨時節點:佔用節點的客戶端由於網絡緣由異常宕機,斷開鏈接,可是沒有執行finally中釋放鎖,使用臨時節點,斷開鏈接就能夠刪除鎖了。
(3)使用臨時有序節點:避免全部的其餘節點都監視一個節點,當這個節點釋放的時候,形成羊羣效應網絡崩潰,使用臨時有序節點,每個節點監視前一個節點就好,集羣式監聽變成鏈式監聽;
(4)使用監聽器(兩個功能中的銷燬功能):其餘SOA客戶端服務須要監聽節點銷燬。
(5)實踐:此功能用來實現分佈式鎖(分佈式鎖三種:mysql、zookeeper、redis)

第四,集羣管理-監聽集羣狀態(臨時節點+監聽器節點刪除)
(1)臨時節點:爲何要建立臨時節點,將一個系統抽象爲一個zookeeper上的一個節點,當這個系統宕機或斷開與zookeeper的鏈接,這個系統就沒有意義了,因此這個節點應該刪除,這是集羣管理-監聽集羣狀態的現實業務需求。爲了知足「當這個系統宕機或斷開與zookeeper的鏈接,這個系統就沒有意義了,因此這個節點應該刪除」,因此,zookeeper爲這個系統的抽象新建的節點,就是臨時節點。
(2)監聽節點刪除:當zookeeper要完成「集羣管理-監聽集羣狀態」的功能,zookeeper上的一個節點就是一個系統的抽象,由於是臨時節點,當這個系統宕機或斷開鏈接,節點被刪除,其餘節點(其餘系統的抽象)固然要能感知到。
(3)實踐:kafka使用zookeeper管理

第五,集羣管理-集羣選主(臨時有序節點+監聽器節點刪除)
(1)臨時節點:爲何要建立臨時節點,將一個系統抽象爲一個zookeeper上的一個節點,當這個系統宕機或斷開與zookeeper的鏈接,這個系統就沒有意義了,因此這個節點應該刪除,這是集羣管理-監聽集羣狀態的現實業務需求。爲了知足「當這個系統宕機或斷開與zookeeper的鏈接,這個系統就沒有意義了,因此這個節點應該刪除」,因此,zookeeper爲這個系統的抽象新建的節點,就是臨時節點。
(2)臨時有序節點:選主須要,選主三比較:

一、比較 epoche紀元(zxid高32bit),若是其餘節點的紀元比本身的大,選舉 epoch大的節點(理由:epoch 表示年代,epoch越大表示數據越新)代碼:(newEpoch > curEpoch);
二、比較 zxid, 若是紀元相同,就比較兩個節點的zxid的大小,選舉 zxid大的節點(理由:zxid 表示節點所提交事務最大的id,zxid越大表明該節點的數據越完整)代碼:(newEpoch == curEpoch) && (newZxid > curZxid);
三、比較 serviceId,若是 epoch和zxid都相等,就比較服務的serverId,選舉 serviceId大的節點(理由: serviceId 表示機器性能,他是在配置zookeeper集羣時肯定的,因此咱們配置zookeeper集羣的時候能夠把服務性能更高的集羣的serverId設置大些,讓性能好的機器擔任leader角色)代碼 :(newEpoch == curEpoch) && ((newZxid == curZxid) && (newId > curId))。

(2)監聽節點刪除:當zookeeper要完成「集羣管理-監聽集羣狀態」的功能,zookeeper上的一個節點就是一個系統的抽象,由於是臨時節點,當這個系統宕機或斷開鏈接,節點被刪除,其餘節點(其餘系統的抽象)固然要能感知到。
(3)實踐:kafka使用zookeeper管理

5、小結

zookeeper兩個結構(ZNode + 監聽器) + zookeeper四個功能(統一配置管理 + 統一命名服務 + 分佈式鎖 + 集羣管理),完成了。

每天打碼,每天進步!!!

相關文章
相關標籤/搜索