走进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四个功能(统一配置管理 + 统一命名服务 + 分布式锁 + 集群管理),完成了。

每天打码,每天进步!!!