走进Zookeeper,剖析内部构造

    科技2022-07-21  117

    文章目录

    一、前言二、分布式存在问题 + zookeeper三个功能 + zookeeper结构 + zookeeper四大功能三、Zookeeper结构:ZNode + 监听器3.1 ZNode3.2 监听器 三、ZooKeeper四个功能(统一配置管理、统一命名服务、分布式锁、集群管理)3.1 统一配置管理:永久节点3.1.1 理论:zookeeper实现统一配置3.1.2 实践:zookeeper实现统一配置3.1.2.1 分布式部署催生统一配置 + 理论上如何实现统一配置 + 实践上zookeeper实现统一配置3.1.2.2 代码:zookeeper实现统一配置3.1.2.2.1 Config:一个传输的Bean对象3.1.2.2.2 ZkConfigMag:提供三个工具方法,读库 写库 写zk3.1.2.2.3 ZkConfigTest:第一个main,修改zookeeper配置3.1.2.2.4 ZkGetConfigClient:第二个main,监听zookeeper修改3.1.2.2.5 输出结果:第一个main,修改zookeeper配置;第二个main,监听zookeeper配置的修改 3.2 统一命名服务:永久节点3.3 分布式锁:临时顺序节点3.4 集群状态:临时顺序节点(监听节点 + 动态选主) 四、面试金手指4.1 zookeeper两个结构:ZNode + 监听器4.2 zookeeper四个功能:统一配置管理 + 统一命名服务 + 分布式锁 + 集群管理4.2.1 zookeeper统一配置管理:永久节点4.2.2 zookeeper实现统一命名服务:永久节点4.2.3 zookeeper实现分布式锁:临时顺序节点4.2.4 zookeeper实现集群管理:临时节点/临时顺序节点4.2.5 小结四个功能如何用两个结构来实现 五、小结

    一、前言

    二、分布式存在问题 + zookeeper三个功能 + zookeeper结构 + zookeeper四大功能

    第一,zookeeper的引入,分布式架构存在的问题:使用分布式系统就无法避免对节点管理的问题(需要实时感知节点的状态、对节点进行统一管理等等),由于这些问题处理起来可能相对麻烦和提高了系统的复杂性,ZooKeeper作为一个能够通用解决这些问题的中间件就应运而生了。

    第二,开发中用到zookeeper的三个地方(kafka 注册中心 分布式锁) 1、Kafka:Kafka使用ZooKeeper进行分布式部署的broker(每一台kafka就是一个broker)的管理,Kafka使用ZooKeeper管理自己的元数据配置。 2、注册中心:和Eureka一样,可以作为注册中心、配置中心。 3、分布式锁:ZooKeeper可以作为分布式锁的一种实现。

    第三,zookeeper结构:树型数据结构,ZNode四种类型节点 + 监听器 第四,zookeeper四个功能(两种结构实现):统一配置管理、统一命名服务、分布式锁、集群管理

    三、Zookeeper结构:ZNode + 监听器

    3.1 ZNode

    ZooKeeper的数据结构,跟Unix文件系统非常类似,可以看做是一颗树,每个节点叫做ZNode。每一个节点可以通过路径来标识,结构图如下:

    那ZooKeeper这颗"树"有什么特点呢?? ZooKeeper的节点我们称之为Znode,Znode分为两种类型: 短暂/临时(Ephemeral):当客户端和服务端断开连接后,所创建的Znode(节点)会自动删除 持久(Persistent):当客户端和服务端断开连接后,所创建的Znode(节点)不会删除

    ZooKeeper和Redis一样,也是C/S结构(分成客户端和服务端)

    3.2 监听器

    在上面我们已经简单知道了ZooKeeper的数据结构了,ZooKeeper的树形数据结构需要配合监听器才能完成四个功能。常见的监听场景有以下两项:

    监听Znode节点的数据变化 监听子节点的增减变化

    小结:通过监听+Znode节点(持久/短暂[临时]),ZooKeeper就可以完成四个功能。

    三、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 分布式锁:临时顺序节点

    金手指:从锁到分布式锁 分布式锁文章链接 分布式锁和进程内的锁本质上是一样的。 1、要互斥,同一时刻只能被一台机器上的一个线程获得。 2、最好支持阻塞,然后唤醒,这样那些等待的线程不用循环重试。 3、最好可以重入(本文没有涉及,参见《编程世界的那把锁》) 4、获得锁和释放锁速度要快 5、对于分布式锁,需要找到一个集中的“地方”(数据库,Redis, Zookeeper等)来保存锁,这个地方最好是高可用的。 6、考虑到“不可靠的”分布式环境, 分布式锁需要设定过期时间 7、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,这样就可以实现动态选举的功能了。

    四、面试金手指

    第一,zookeeper的引入,分布式架构存在的问题:使用分布式系统就无法避免对节点管理的问题(需要实时感知节点的状态、对节点进行统一管理等等),由于这些问题处理起来可能相对麻烦和提高了系统的复杂性,ZooKeeper作为一个能够通用解决这些问题的中间件就应运而生了。

    第二,开发中用到zookeeper的三个地方(kafka 注册中心 分布式锁) 1、Kafka:Kafka使用ZooKeeper进行分布式部署的broker(每一台kafka就是一个broker)的管理,Kafka使用ZooKeeper管理自己的元数据配置。 2、注册中心:和Eureka一样,可以作为注册中心、配置中心。 3、分布式锁: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实现分布式锁:临时顺序节点

    金手指:从锁到分布式锁 分布式锁文章链接 分布式锁和进程内的锁本质上是一样的。 1、要互斥,同一时刻只能被一台机器上的一个线程获得。 2、最好支持阻塞,然后唤醒,这样那些等待的线程不用循环重试。 3、最好可以重入(本文没有涉及,参见《编程世界的那把锁》) 4、获得锁和释放锁速度要快 5、对于分布式锁,需要找到一个集中的“地方”(数据库,Redis, Zookeeper等)来保存锁,这个地方最好是高可用的。 6、考虑到“不可靠的”分布式环境, 分布式锁需要设定过期时间 7、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)临时有序节点:选主需要,选主三比较:

    1、比较 epoche纪元(zxid高32bit),如果其他节点的纪元比自己的大,选举 epoch大的节点(理由:epoch 表示年代,epoch越大表示数据越新)代码:(newEpoch > curEpoch); 2、比较 zxid, 如果纪元相同,就比较两个节点的zxid的大小,选举 zxid大的节点(理由:zxid 表示节点所提交事务最大的id,zxid越大代表该节点的数据越完整)代码:(newEpoch == curEpoch) && (newZxid > curZxid); 3、比较 serviceId,如果 epoch和zxid都相等,就比较服务的serverId,选举 serviceId大的节点(理由: serviceId 表示机器性能,他是在配置zookeeper集群时确定的,所以我们配置zookeeper集群的时候可以把服务性能更高的集群的serverId设置大些,让性能好的机器担任leader角色)代码 :(newEpoch == curEpoch) && ((newZxid == curZxid) && (newId > curId))。

    (2)监听节点删除:当zookeeper要完成“集群管理-监听集群状态”的功能,zookeeper上的一个节点就是一个系统的抽象,因为是临时节点,当这个系统宕机或断开连接,节点被删除,其他节点(其他系统的抽象)当然要能感知到。 (3)实践:kafka使用zookeeper管理。

    五、小结

    zookeeper两个结构(ZNode + 监听器) + zookeeper四个功能(统一配置管理 + 统一命名服务 + 分布式锁 + 集群管理),完成了。

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

    Processed: 0.009, SQL: 8