• 服务框架Dubbo和ZooKeeper



    本篇为动物园之旅~
    dubbo看作动物园的动物,那么zookeeper就是动物园
    如果有人想去动物园看小老虎,那么动物园中有小老虎才能看到,否则看不到~

    关系:dubbo与 zookeeper的关系 Dubbo建议使用Zookeeper作为服务的注册中心

    一.Dubbo框架(远程过程调用)

    1.分布式系统中的相关概念

    • 大型互联网项目的架构目标

    传统项目和互联网项目
    在这里插入图片描述

    大型互联网项目的架构目标
    在这里插入图片描述

    • 集群和分布式

    两者区别

    在这里插入图片描述

    没有集群和分布式的服务器

    在这里插入图片描述
    进行集群的服务器-可以进行负载均衡,实现了高性能、高可用的目标

    在这里插入图片描述

    同时进行集群和分布式的服务器-除了集群实现的功能和目标,还可以实现可伸缩、高可扩展的目标
    在这里插入图片描述

    集群和分布式的理解
    在这里插入图片描述

    • 架构演进

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    2.Dubbo概述

    • Dubbo概念

    Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用智能容错负载均衡,以及服务自动注册和发现。

    Dubbo是微服务开发框架,提供RPC通信微服务治理的能力

    • Dubbo架构

    Dubbo 基于消费端的自动服务发现能力

    在这里插入图片描述

    服务发现,c能力,是微服务框架需要具备的关键能力,借助于自动化的服务发现,微服务之间可以在无需感知对端部署位置与 IP 地址的情况下实现通信。

    实现服务发现的方式有很多种,Dubbo 提供的是一种 Client-Based 的服务发现机制,通常还需要部署额外的第三方注册中心组件来协调服务发现过程,如常用的 Nacos、Consul、Zookeeper 等,Dubbo 自身也提供了对多种注册中心组件的对接,用户可以灵活选择。

    服务发现的一个核心组件是注册中心,Provider 注册地址到注册中心,Consumer 从注册中心读取和订阅 Provider 地址列表。

    下图是 Dubbo2 的服务发现模型:Provider 注册服务地址,Consumer 经过注册中心协调并发现服务地址,进而对地址发起通信,这是被绝大多数微服务框架的经典服务发现流程。而 Dubbo2 的特殊之处在于,它把 “RPC 接口”的信息也融合在了地址发现过程中,而这部分信息往往是和具体的业务定义密切相关的。

    在这里插入图片描述

    3.Dubbo快速入门

    使用zookeeper作为注册中心

    在这里插入图片描述

    在这里插入图片描述

    4.Dubbo高级特性

    • dubbo-admin管理平台

    在这里插入图片描述

    • dubbo高级特性

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    二.ZooKeeper框架(分布式协调服务)

    1.ZooKeeper主要功能

    1.1 配置管理

    分布式项目的配置总管理处
    在这里插入图片描述

    1.2 分布式锁

    对于分布式项目修改共享数据时加入锁管理(同一时间只能有一个服务对数据进更改)
    在这里插入图片描述

    1.3 集群管理

    最常见的功能,作为注册中心使用.

    在这里插入图片描述

    2.ZooKeeper命令操作

    在这里插入图片描述

    2.1 ZooKeeper数据模型

    • Zookeeper是一个树形目录服务,其数据模型和Unix的文件系统目录树很类似,拥有一个层次化结构

    • 这里面的每一个结点都被称为ZNode,每个节点都会保存自己的数据和节点信息

    • 节点可以拥有子节点,同时也允许少量(1MB)数据存储在该节点之下

    • 节点可以分为四大类

      • PERSISTENT 持久化节点

      • EPHEMRAL 临时节点 : -e

      • PERSISTENT_SENQUENTIAL 持久化顺序节点 : -s

      • EPHEMRAL_SEQUENTIAL 临时顺序节点 : -es

    在这里插入图片描述

    2.2 ZooKeeper 服务端常用命令

    在安装目录的bin目录下:

    • 启动Zookeeper服务 : ./zkServer.sh start

    • 查看Zookeeper服务状态 : ./zkServer.sh statu

    • 停止Zookeeper服务 : ./zkServer.sh stop

    • 重启Zookeeper服务 : ./zkServer.sh restart

    2.3 ZooKeeper 客户端常用命令

    • 连接ZooKeeper服务端
    ./zkCli.sh -server ip:port
    
    • 1
    • 断开客户端连接
    quit
    
    • 1
    • 设置节点的值
    set /节点path value
    
    • 1
    • 查看帮助命令
    help
    
    • 1
    • 删除单个节点
    delete /节点path
    
    • 1
    • 显示指定目录下的节点
    ls 目录
    
    • 1
    • 删除带有子节点的节点
    deleteall /节点path
    
    • 1
    • 创建节点
    create /节点path value
    
    • 1
    • 获取节点的值
    get /节点path
    
    • 1
    • 创建临时节点
    create -e /节点path value
    
    • 1
    • 创建顺序节点
    create -s /节点path value
    
    • 1
    • 查询节点详细信息
    ls -s /节点path
    
    • 1
    • 节点详细信息
    czxid : 节点被创建的事务ID
    
    dataversion : 数据版本号
    
    ctime : 创建时间
    
    aclversion : 权限版本号
    
    mzxid : 最后一次被更新的事务ID
    
    ephemeralOwner : 用于临时节点 ,代表临时节点的事务ID,如果为持久节点则为0
    
    pzxid : 子节点列表最后一次被更新的事务ID
    
    dataLength : 节点存储的数据长度
    
    cversion : 子节点的版本号
    
    numChildren : 当前节点的子节点数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3.Java API-Curator

    Curator是Apache ZooKeeper的Java客户端库
    官网:https://curator.apache.org/

    依赖:

    <dependency>
    <groupId>org.apache.curatorgroupId>
    <artifactId>curator-frameworkartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    4.Java API 常用操作

    • 建立连接

    • 添加节点

    • 删除节点

    • 修改节点

    • 查询节点

    • Watch时间监听

    • 分布式锁实现

    4.1 建立连接

    4.1.1 方式一
    /**
           * Create a new client
           * Params:
           * connectString – "192.168.36.100:2181,192.168.36.101:2181"
           * sessionTimeoutMs – 会话超时时间 单位ms
           * connectionTimeoutMs – 连接超时时间 单位ms
           * retryPolicy – 重试策略
           * Returns:
           * client
           */
          //重试策略 每间隔x一共重试x次  每隔3秒连接一次一共连接10次
          RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
          //1.第一种方式
          CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.36.100:2181"
                  , 60 * 1000, 15 * 1000, retryPolicy);
          //开启连接
          client.start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    4.1.2 方式二 : 链式编程(有提示)
    //2.第二种方式
    client = CuratorFrameworkFactory.builder()
            .connectString("192.168.36.100:2181")
            .sessionTimeoutMs(60 * 1000)
            .connectionTimeoutMs(15 * 1000)
            .retryPolicy(retryPolicy)
            .namespace("jmpower")
            .build();
    
    //开启连接
    client.start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • namespace : 创建根节点jmpower(为了方便,不用之后每次进行客户端操作都写/根节点path)

    4.2 添加节点

    创建结点:create 持久化 临时 顺序 数据
    1.基本创建 : create().forPath(“”)
    2.创建结点,带有数据 : create().forPath(“”,data)
    3.设计节点类型 : create().withMode().forPath(“”)
    4.创建多级节点 /app1/p1 : create().creatingParentsIfNeeded().forPath(“”)

    4.2.1 基本创建
     @Test
     public void testCreate() throws Exception {
         //1.基本创建
         String path = client.create().forPath("/app1");
         System.out.println(path);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    4.2.2 创建带有数据的结点
     @Test
     public void testCreate2() throws Exception {
         //2.创建结点,带有数据
         //如果创建的节点,没有指定数据,则默认将当前客户端的ip作为数据存储
         String path = client.create().forPath("/app2", "hehe".getBytes());
         System.out.println(path);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    4.2.3 设计节点类型
     @Test
     public void testCreate3() throws Exception {
         //3.设计节点类型
         //默认类型:持久化
         String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3");
         System.out.println(path);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    4.2.4 创建多级节点
     @Test
     public void testCreate4() throws Exception {
         //4.创建多级节点 /app1/p1
         //creatingParentsIfNeeded():如果父节点不存在,则创建父节点
         String path = client.create().creatingParentsIfNeeded().forPath("/app4/p1");
         System.out.println(path);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.3 删除节点

    删除节点:delete deleteall
    1.删除单个节点 : delete().forPath()
    2.删除带有子节点的节点 : delete().deletingChildrenIfNeeded().forPath()
    3.必须成功的删除(为了防止网路抖动,本质就是重试) : delete().guaranteed().forPath()
    4.回调 : inBackground

    4.3.1 删除单个节点
      @Test
      public void testDelete() throws Exception {
          //1.删除单个节点
          client.delete().forPath("/app1");
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    4.3.2 删除带有子节点的节点
      @Test
      public void testDelete2() throws Exception {
          //2.删除带有子节点的节点
          client.delete().deletingChildrenIfNeeded().forPath("/app4");
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    4.3.3 必须成功的删除
      @Test
      public void testDelete3() throws Exception {
          //3.必须成功的删除
          client.delete().guaranteed().forPath("/app2");
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    4.3.4 回调
      @Test
      public void testDelete4() throws Exception {
          //4.回调
          client.delete().guaranteed().inBackground(new BackgroundCallback() {
              @Override
              public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
                  System.out.println("我被删除了~");
                  System.out.println(event);
              }
          }).forPath("/app1");
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4.4 修改节点

    修改数据
    1.修改数据 : setData().forPath()
    2.根据版本修改 : setData().withVersion(version).forPath()
    version是通过查询出来的。目的就是为了让其他客户端或线程不干扰我。

    4.4.1 修改数据
    @Test
    public void testSet() throws Exception {
       client.setData().forPath("/app1","jm666".getBytes());
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    4.4.2 根据版本修改
    @Test
    public void testSetForVersion() throws Exception {
        Stat stat = new Stat();
        //3.查询节点的状态信息:ls -s
        client.getData().storingStatIn(stat).forPath("/app1");
    
        int version=stat.getVersion();//查询出来的版本号
        System.out.println(version);
        client.setData().withVersion(version).forPath("/app1","hahaha".getBytes());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.5 查询节点

    查询节点:
    1.查询数据:get : getData().forPath(“”)
    2.查询子节点:ls : getChildren().forPath(“”)
    3.查询节点的状态信息:ls -s : getData().storingStatIn(stat).forPath(“”)

    4.5.1 查询数据
    @Test
    public void testGet() throws Exception {
        //1.查询数据:get
        byte[] data = client.getData().forPath("/app1");
        System.out.println(new String(data));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    4.5.2 查询子节点
    @Test
    public void testGet2() throws Exception {
        //2.查询子节点:ls
        List<String> path = client.getChildren().forPath("/");
        System.out.println(path);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    4.5.3 查询节点的状态信息
    @Test
    public void testGet3() throws Exception {
        Stat stat = new Stat();
        //3.查询节点的状态信息:ls -s
        client.getData().storingStatIn(stat).forPath("/app1");
        System.out.println(stat);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5.Watch事件监听

    5.1 基本概念

    • ZooKeeper允许用户在指定节点上注册一些Watchr,并且在一些特定事件触发的时候,ZooKeeper服务端会将事件通知到感兴趣的客户端上去,该机制时ZooKeeper实现分布式协调服务的重要特性.

    • ZooKeeper中引入了Watcher机制来实现了发布/订阅功能.能够让多个订阅者同时监听某一个对象,当一个对象自身状态变化的时候,会通知所有订阅者.

    • ZooKeeper原生支持通过注册Watcher来进行事件监听,但是其使用并不是特别方便需要开发人员自己反复注册Watcher,比较繁琐.

    • Curator引入了Cache来实现对ZooKeeper服务端事件的监听.

    • ZooKeeper提供了三种Watcher:

      • NodeCache : 只是监听了某一特定节点

      • PathChildrenCache : 监控一个ZNode的子节点

      • TreeCache : 可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCache组合.

    5.1 NodeCache

    /**
     * nodeCache:监听某个节点
     */
    @Test
    public void testNodeCatch() throws Exception {
        //1.创建NodeCatch对象
        NodeCache nodeCache = new NodeCache(client, "/app1");
        //2.注册监听
        nodeCache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                System.out.println("节点变化了~");
                //获取节点更改后的数据
                byte[] data = nodeCache.getCurrentData().getData();
                System.out.println(new String(data));
            }
        });
        //3.开启监听,如果设置为true,则开启监听,加载缓冲数据
        nodeCache.start(true);
    
        while (true){
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    5.2 PathChildrenCache

    /**
     * PathChildrenCache:监听某个节点的所有子节点们
     */
    @Test
    public void testPathChildrenCache() throws Exception {
        //1.创建监听对象
        PathChildrenCache pathChildrenCache = new PathChildrenCache(client,"/app2",true);
        //2.绑定监听器
        pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
                System.out.println("子节点变化了~");
                System.out.println(pathChildrenCacheEvent);
                //监听子节点的数据变更,并且拿到变更后的数据
                //1.获取类型
                PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
                //2.判断类型是否为update
                if (type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
                    System.out.println("数据变了!!!");
                    byte[] data = pathChildrenCacheEvent.getData().getData();
                    System.out.println(new String(data));
                }
            }
        });
        //3.开启
        pathChildrenCache.start();
    
        while (true) {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    5.3 TreeCache

    /**
     * TreeCache:监听某个节点的所有子节点们
     */
    @Test
    public void testTreeCache() throws Exception {
        //1.创建监听器
        TreeCache treeCache = new TreeCache(client, "/app2");
        //2.注册监听器
        treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
                System.out.println("节点变化了~");
                System.out.println(treeCacheEvent);
                if(treeCacheEvent.getType()== TreeCacheEvent.Type.NODE_UPDATED){
                    System.out.println("更改操作!!");
                }
            }
        });
        //3.开启
        treeCache.start();
    
        while (true){
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    6.分布式锁

    在这里插入图片描述

    6.1 分布式锁

    • 在我们进行单机应用开发,涉及并发同步的时候,我们往往采用synchronized或者lock的方式来解决多线程见的代码同步问题,这时多线程的运行都是运行在同一 JVM下,没有任何问题

    • 但当我们的应用时分布式集群工作的情况下,属于JVM下的工作环境,跨JVM之间已经无法通过多线程的锁解决同步问题

    • 那么久需要一种更加高级的锁机制,来处理跨机器的进程之间的数据同步问题—这就是分布式锁.

    6.2 分布式锁原理

    • 核心思想 : 当客户端要获取锁,则创建节点,使用完锁则删除该节点

      • 客户端获取锁时,在lock节点下创建临时顺序节点

      • 然后分别获取lock下面的所有子节点,客户端获取到所有子节点之后,如果发现自己创建的子节点序号最小,那么就认为该客户端获取到了锁.

      • 如果发现自己创建的节点并非lock所有子节点中最小的,说明还没有获取到锁,此时客户端需要找到比自己小的那个节点,同时对其注册事件监听器,监听删除事件.

      • 如果发现比自己小得那个节点被删除,则客户端的Watcher会受到相应通知,此时再次判断自己创建的节点是否是lock子节点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取比自己小的一个节点并注册监听.

    6.3 模拟12306售票案例

    • 在Curator中有五种锁方案

      • InterProcessSemaphoreMutex : 分布式排它锁 (非可重入锁)

      • InterProcessMutex : 分布式可重入排它锁

      • InterProcessReadWriteLock : 分布式读写锁

      • InterProcessMultiLock : 将多个锁作为单个实体管理的容器

      • InterProcessSemaphoreV2 : 共享信号量

    在这里插入图片描述

    Runnable

    package com.jm.curator;
    
    import org.apache.curator.RetryPolicy;
    import org.apache.curator.framework.CuratorFramework;
    import org.apache.curator.framework.CuratorFrameworkFactory;
    import org.apache.curator.framework.recipes.locks.InterProcessMutex;
    import org.apache.curator.retry.ExponentialBackoffRetry;
    
    import java.util.concurrent.TimeUnit;
    
    public class Ticket12306 implements Runnable{
        private int tickets=10;//数据库的票数
    
        private InterProcessMutex lock;
    
        public Ticket12306(){
            //重试策略
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString("192.168.36.100:2181")
                    .sessionTimeoutMs(60 * 1000)
                    .connectionTimeoutMs(15 * 1000)
                    .retryPolicy(retryPolicy)
                    .build();
    
            //开启连接
            client.start();
    
            lock=new InterProcessMutex(client,"/lock");
        }
    
        @Override
        public void run() {
            while(true){
                //获取锁
                try {
                    lock.acquire(3, TimeUnit.SECONDS);
                    if(tickets>0){
                        System.out.println(Thread.currentThread()+":"+tickets);
                        Thread.sleep(100);
                        tickets--;
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }finally {
                    //释放锁
                    try {
                        lock.release();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    Main

    package com.jm.curator;
    
    public class LockTest {
        public static void main(String[] args) {
            Ticket12306 ticket12306=new Ticket12306();
    
            //创建客户端
            Thread t1=new Thread(ticket12306,"携程");
            Thread t2=new Thread(ticket12306,"飞猪");
    
            t1.start();
            t2.start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    7.ZooKeeper集群

    7.1 集群简介

    最典型集群模式:Master/Slave 模式(主备模式)。在这种模式中,通常 Master 服务器作为主服务器提供写服务,其他的 Slave 服务器从服务器通过异步复制的方式获取 Master 服务器最新的数据提供读服务。

    7.2 ZooKeeper集群搭建

    与创建单机环境类似

    修改conf目录下的zoo_sample.cfg为zoo.cfg

    修改data目录为指定目录,每个集群成员分别配置

    在data目录下创建myid文件,内容分别为1,2,3

    分别在conf目录下的zoo.cfg文件加入如下内容

    server.1=192.168.149.135:2881:3881
    server.2=192.168.149.135:2882:3882
    server.3=192.168.149.135:2883:3883
    
    • 1
    • 2
    • 3
    • 解释:server.服务器ID=服务器IP地址:服务器之间通信端口:服务器之间投票选举端口,搭建伪集群,端口可以写成127.0.0.1

    7.3 ZooKeeper集群角色

    • Leader领导者

      • 处理事务请求(增删改)

      • 集群内部各个服务器的调度者

    • Follower跟随者

      • 处理客户端非事务请求(查),转发事务请求给Leader服务器.

      • 参数Leader选举投票

    • Observer观察者

      • 处理客户端非事务请求,转发事务请求给Leader服务器.

    7.4 ZooKeeper 集群中的服务器状态

    • LOOKING :寻找 Leader。
    • LEADING :Leader 状态,对应的节点为 Leader。
    • FOLLOWING :Follower 状态,对应的节点为 Follower。
    • OBSERVING :Observer 状态,对应节点为 Observer,该节点不参与 Leader 选举。

    7.5 ZooKeeper选举流程

    • Leader选举 :

      • Serverid ; 服务器ID

        • 比如有三台机器,编号为1,2,3.编号越大在选择算法中权重越大.
      • Zxid : 数据ID

        • 服务器中存放的最大数据ID,值越大说明数据越新,在选举算法中数据越新则权重越大
      • 在Leader选举的过程中,如果某台ZooKeeper获得了超过半数的选票,则此ZooKeeper就可以成为Leader了

    每个节点都有自己携带的唯一id

    • 1.启动第一台机器1,发起选举,自己投票给自己,票数不过半,选举失败,服务器1保持looking状态。

    • 2.启动第二台机器2,发起选举,1和2都先给自己投一票,1发现2 比自己的id大,所以把自己的票也投给服务器2,此时服务器2有2票,服务器1有0票,票数不过半,选举失败。服务器1,2均保持looking 状态

    • 3.启动第三台机器3,发起选举,1,2,3都先给自己投上一票,但是1和2发现服务器3的id比自己大,所以把自己的票都投给服务器3,次数服务器3票数过半,选举成功,服务器3当选leader服务器1,2变为follower,服务器3变为leader.此时已经选举成功了,后面两台机器的选举不会改变结果

    • 4.启动第四台机器
      发起一次选举,此时服务器1,2,3是folllower 状态,不会更改选票信息。此时:服务器3为3票,服务器4为1票。服务器4少数服从多数,更改选票信息为服务器3。服务器4更改状态为follower

    • 5.启动第五台机器
      与服务器4一样投票给3,此时服务器3一共5票,服务器5为0票。服务器5更改状态为follower

  • 相关阅读:
    安达发|制造业的新趋势:APS排程软件的广泛应用
    【FreeRTOS】10 事件标志组
    QT摄像头采集
    idea工具,debug模式小技巧,调试正确姿势。快进收藏夹。
    ubuntu20.04运用startup application开机自启动python程序
    智能网卡的网络加速技术
    算法12.从暴力递归到动态规划5
    excel、word、ppt 下载安装步骤整理
    如何利用腾讯云轻量应用服务器五分钟搭建一个WordPress博客?
    软件设计之抽象工厂模式
  • 原文地址:https://blog.csdn.net/m0_66689823/article/details/127710458