Zookeeper从入门到实战(附企业面试题)

1.概述

Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。

Zookeeper从设计模式角度来理解,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生了变化,Zookeeper就负责通知已经在Zookeeper上注册的那些观察者做出相应的反应.

Zookeeper = 文件系统 + 通知机制

1.1 工作机制

在这里插入图片描述

1.2 特点

在这里插入图片描述

1.3 数据结构

在这里插入图片描述

ZK中的数据保存的格式(树状结构)

注意:ZK中没有文件的概念,节点下直接存的就是内容。

1.4 应用场景

提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。

统一命名服务:

在分布式环境下,经常需要对应用/服务进行统一命令,便于识别。例如:IP不容易记住,而域名容易记住。

在这里插入图片描述

统一配置管理:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LDG6MZdR-1638621332236)(/image-20211204140338034.png)]

统一集群管理:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TbJ9t5WS-1638621332237)(/image-20211204140358226.png)]

服务器动态上下线:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-na3XpuEI-1638621332237)(/image-20211204140434735.png)]

软负载均衡:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bB3pSaXk-1638621332237)(/image-20211204140500722.png)]

2 Zookeeper单点安装

2.1 安装

1.把软件包上传到Linux的/opt/software下

2.解压ZK到/opt/module下

3.将解压后的目录名称修改一下(选做)

4.将ZK的安装目录下conf/zoo_sample.cfg文件改名为zoo.cfg

5.在ZK的安装目录下创建一个新的目录,作为zk的数据持久化目录

​ 修改zoo.cfg配置文件

​ dataDir = /opt/module/zooker-3.5.7/zkData

6.配置ZK的环境变量(选做)

单点模式的简单操作

1.启动zk服务端和 zk客户端

zkServer.sh start zkCli.sh -server host:port

2.查看一下zk的服务端和客户端对应的进程

QuorumPeerMain --> 服务端

ZookeeperMain --> 客户端

3.退出客户端

quit

2.2 配置参数解读

Zookeeper中的配置文件zoo.cfg中参数含义解读如下:

1)tickTime =2000,通信心跳数,Zookeeper服务器客户端心跳时间,单位毫秒

Zookeeper使用的基本时间,服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个tickTime时间就会发送一个心跳,时间单位为毫秒。

它用于心跳机制,并且设置最小的session超时时间为两倍心跳时间。(session的最小超时时间是2*tickTime)

2)initLimit =10:LF初始通信时限

集群中的Follower跟随者服务器与Leader领导者服务器之间初始连接时能容忍的最多心跳数(tickTime的数量),用它来限定集群中的Zookeeper服务器连接到Leader的时限。

3)syncLimit =5:LF同步通信时限

集群中Leader与Follower之间的最大响应时间单位,假如响应超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer。

4)dataDir:数据文件目录+数据持久化路径

主要用于保存Zookeeper中的数据。

5)clientPort =2181:客户端连接端口

监听客户端连接的端口。

3 Zookeeper实战(开发重点)

注意事项:如果不是第一次搭建集群,那么就把zk安装目录下的zkData目录删除,并且把logs目录也删除

3.1 分布式安装部署

1)集群规划

在hadoop201、hadoop202和hadoop203三个节点上部署Zookeeper。

2)解压安装

3)修改201配置文件

clientPort=2181
server.2=hadoop201:2888:3888
server.3=hadoop202:2888:3888
server.4=hadoop203:2888:3888

server.A=B:C:D。
A是一个数字,表示这个是第几号服务器;
集群模式下配置一个文件myid,这个文件在dataDir目录下,这个文件里面有一个数据就是A的值,Zookeeper启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server。
B是这个服务器的地址;
C是这个服务器Follower与集群中的Leader服务器交换信息的端口;
D是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。

4)编辑myid文件

在zkData下新建myid 编辑2

5)分发文件

修改202 和203 的myid

6)编写集群启动脚本

#!/bin/bash
if [ $# -lt 1 ]
then
 echo '参数不能为空!!!'
 exit
fi

for host in hadoop201 hadoop202 hadoop203
do
  case $1 in
  "start")
  echo "$**********$host****ZK启动*****************"
  ssh $host /opt/module/zookeeper-3.5.7/bin/zkServer.sh $1
  ;;
  "stop")
  echo "$**********$host****ZK停止*****************"
  ssh $host /opt/module/zookeeper-3.5.7/bin/zkServer.sh $1
  ;;
  "status")
  echo "$**********$host****ZK状态*****************"
  ssh $host /opt/module/zookeeper-3.5.7/bin/zkServer.sh $1
  ;;
  "*")
  echo '参数有误!!!'
  exit
  ;;
  esac
done

3.2 客户端命令行操作

命令基本语法功能描述
help显示所有操作命令
ls path使用 ls 命令来查看当前znode的子节点-w 监听子节点变化-s 附加次级信息
create普通创建-s 含有序列-e 临时(重启或者超时消失)
get path获得节点的值-w 监听节点内容变化-s 附加次级信息
set设置节点的具体值
stat查看节点状态
delete删除节点
deleteall递归删除节点
1.查看当前znode中所包含的内容

[zk: hadoop201:2181(CONNECTED) 6] ls /
[zookeeper]

2.查看当前节点详细数据
[zk: hadoop201:2181(CONNECTED) 5] ls -s /
[zookeeper]cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1

3.分别创建2个普通节点
[zk: hadoop201:2181(CONNECTED) 9] create /sanguo  创建持久化节点
Created /sanguo
[zk: hadoop201:2181(CONNECTED) 13] create -e /xiyou   创建临时节点
Created /xiyou
[zk: hadoop201:2181(CONNECTED) 4] create -s /honglou   创建带序号持久化节点 从零开始 把以前创建的节点也算上
Created /honglou0000000002
[zk: hadoop201:2181(CONNECTED) 6] create -s -e /shuihu    创建带序号临时节点
Created /shuihu0000000003

4. 获得节点的值
[zk: hadoop201:2181(CONNECTED) 3] set /sanguo "zhugeliang"  设置值
[zk: hadoop201:2181(CONNECTED) 4] get /sanguo               获取值
zhugeliang
从新设置会覆盖 不会追加

[zk: hadoop203:2181(CONNECTED) 2] get -w /sanguo  设置监听节点内容
huangyueying
[zk: hadoop203:2181(CONNECTED) 3] 
WATCHER::

WatchedEvent state:SyncConnected type:NodeDataChanged path:/sanguo

[zk: hadoop203:2181(CONNECTED) 1] ls -w /sanguo  设置监听节点名称
[shuhan]
[zk: hadoop203:2181(CONNECTED) 2] 
WATCHER::

WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/sanguo

查看节点状态  元数据
[zk: hadoop203:2181(CONNECTED) 2] stat /
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x20000000a
cversion = 5
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 3

删除空节点
[zk: hadoop203:2181(CONNECTED) 4] delete /honglou0000000002
删除非空节点
[zk: hadoop203:2181(CONNECTED) 5] deleteall /sanguo
[zk: hadoop203:2181(CONNECTED) 6] ls /
[zookeeper]

3.3 API应用

3.3.1 IDEA环境搭建

1)创建一个MavenModule

2)添加pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zookeepe</groupId>
    <artifactId>Zookeepe</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.5.7</version>
        </dependency>
    </dependencies>
    
</project>

3)拷贝log4j.properties文件到项目根目录

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
3.3.2 初始化ZooKeeper客户端
/**
 * 1.获取ZK客户端连接对象
 * 2.调用相关API完成对应的功能
 * 3.关闭资源
 */
public class ZookeeperTest {
    /**
     * connectString : 连接ZK服务的地址 hadoop201:2181,hadoop202:2181,hadoop203:2181
     * sessionTimeout : 超时时间
     * new Watcher() : 
     */
    @Test
    public void testCreateZookeeperClient() throws IOException, InterruptedException {
        String connectStr = "hadoop201:2181,hadoop202:2181,hadoop203:2181";
        int sessionTimeout = 10000;  
        ZooKeeper zooKeeper = new ZooKeeper(connectStr, sessionTimeout, new Watcher() {
            public void process(WatchedEvent event) {
                System.out.println("根据具体的业务进行下一步操作。。。");
            }
        });

        System.out.println(zooKeeper);
        
        //关闭连接
        zooKeeper.close();
    }
}
3.3.3 其它API操作
package com.zk;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.time.Period;
import java.util.List;

/**
 * 1.获取ZK客户端连接对象
 * 2.调用相关API完成对应的功能
 * 3.关闭资源
 */
public class ZookeeperTest {
    private ZooKeeper zk;


    /**
     * 创建节点
     * 1.path: 指定创建节点的路径
     * 2.data : 节点内容
     * 3.acl:对操作用户的权限控制
     * 4.CreateMode : 创建节点格式 是否持久 是否带序号
     */
    @Test
    public void testCreateNode() throws KeeperException, InterruptedException {
        zk.create("/xiyou",
                "rulai".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.PERSISTENT);
    }

    /**
     * 获取子节点
     * getChildren
     * path: 路径
     * boolean watch : 是否监控
     */
    @Test
    public void testGetChildren() throws KeeperException, InterruptedException {
        //获取子节点不监控
//        List<String> children = zk.getChildren("/", false);
//        for (String child : children) {
//            System.out.println(child);
//        }
        //监控
        List<String> children = zk.getChildren("/", new Watcher() {
            public void process(WatchedEvent event) {
                System.out.println("发现根目录下的节点有变化");
            }
        });
        for (String child : children) {
            System.out.println(child);
        }
        Thread.sleep(Long.MAX_VALUE);
    }

    /**
     * 判断节点是否存在
     */
    @Test
    public void testExist() throws KeeperException, InterruptedException {
        Stat stat = zk.exists("/sanguo", false);
        if (stat == null){
            System.out.println("不存在");
        }else {
            System.out.println("存在"+ stat.toString());
        }
    }

    /**
     * 获取节点的数据,不监听
     * path
     * watch
     * stat
     */
    @Test
    public void testGetData() throws KeeperException, InterruptedException {
        //封装一个path
        String path = "/sanguo";
        //判断当前节点是否存在
        Stat stat = zk.exists(path, false);
        if (stat == null){
            System.out.println("不存在");
        }else {
            byte[] datas = zk.getData(path, false, stat);
            System.out.println(new String(datas));
        }
    }


    /**
     * 获取节点值
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testGetDataWatch() throws KeeperException, InterruptedException {
        //封装一个path
        String path = "/sanguo";
        //判断当前节点是否存在
        Stat stat = zk.exists(path, false);
        if (stat == null){
            System.out.println("不存在");
        }else {
            byte[] datas = zk.getData(path, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    System.out.println("节点的值改变了");
                }
            }, stat);
            System.out.println(new String(datas));
        }
        Thread.sleep(Long.MAX_VALUE);
    }

    /**
     * 设置节点值
     * path
     * data[]
     * version
     */
    @Test
    public void setNodeData() throws KeeperException, InterruptedException {
        //封装一个path
        String path = "/sanguo";
        //判断当前节点是否存在
        Stat stat = zk.exists(path, false);
        if (stat == null){
            System.out.println("不存在");
        }else {
           //zk.setData(path, "guanerye,abei,agfei".getBytes(), stat.getVersion());
            //-1代表不检测版本
           zk.setData(path, "guanerye,abei,agfei1".getBytes(), -1);
        }
    }


    /**
     * 删除空节点,没有字节点
     */
    @Test
    public void deleteNode() throws KeeperException, InterruptedException {
        //封装一个path
        String path = "/a";
        //判断当前节点是否存在
        Stat stat = zk.exists(path, false);
        if (stat == null){
            System.out.println("不存在");
        }else {
           zk.delete(path, stat.getVersion());
        }
    }


    /**
     * 测试递归删除节点
     */
    @Test
    public void testDeleteAll() throws KeeperException, InterruptedException {
        deleteNodeAll("/a", zk);
    }


    public void deleteNodeAll(String path, ZooKeeper zk) throws KeeperException, InterruptedException {
        //判断节点是否存在
        Stat stat = zk.exists(path, false);
        if (stat == null) {
            System.out.println("节点不存在...");
            return;
        }
        //先获取当前传入节点下的所有子节点
        List<String> children = zk.getChildren(path, false);
        if (children.isEmpty()) {
            //说明传入的节点没有子节点,可以直接删除
            zk.delete(path, stat.getVersion());
        } else {
            //如果传入的节点有子节点,循环所有子节点
            for (String child : children) {
                //删除子节点,但是不知道子节点下面还有没有子节点,所以递归调用
                deleteNodeAll(path + "/" + child, zk);
            }
            //删除完所有子节点以后,记得删除传入的节点
            zk.delete(path, stat.getVersion());
        }
    }





    /**
     * 获取连接对象
     */
    @Before
    public void init() throws IOException {
        String connectStr = "hadoop201:2181,hadoop202:2181,hadoop203:2181";
        int sessionTimeout = 10000;
        zk = new ZooKeeper(connectStr, sessionTimeout, new Watcher() {
            public void process(WatchedEvent event) {
            }
        });
    }

    /**
     * 关闭资源
     */
    @After
    public void close(){
        try {
            if (zk != null){
                zk.close();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * connectString : 连接ZK服务的地址 hadoop201:2181,hadoop202:2181,hadoop203:2181
     * sessionTimeout : 超时时间
     * new Watcher() :
     */
    @Test
    public void testCreateZookeeperClient() throws IOException, InterruptedException {
        String connectStr = "hadoop201:2181,hadoop202:2181,hadoop203:2181";
        int sessionTimeout = 10000;
        ZooKeeper zooKeeper = new ZooKeeper(connectStr, sessionTimeout, new Watcher() {
            public void process(WatchedEvent event) {
                System.out.println("根据具体的业务进行下一步操作。。。");
            }
        });

        System.out.println("ZK:**********" + zooKeeper);

        //关闭连接
        zooKeeper.close();
    }
}

4 Zookeeper内部原理

4.1 节点类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4W8wAP5m-1638621332238)(/image-20211204194808073.png)]

4.2 Stat结构体

(1)czxid-创建节点的事务zxid

每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。

事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid,如果zxid1小于zxid2,那么zxid1在zxid2之前发生。

(2)ctime - znode被创建的毫秒数(从1970年开始)

(3)mzxid - znode最后更新的事务zxid

(4)mtime - znode最后修改的毫秒数(从1970年开始)

(5)pZxid-znode最后更新的子节点zxid

(6)cversion - znode子节点变化号,znode子节点修改次数

(7)dataversion - znode数据变化号

(8)aclVersion - znode访问控制列表的变化号

(9)ephemeralOwner- 如果是临时节点,这个是znode拥有者的session id。如果不是临时节点则是0。

(10)dataLength- znode的数据长度 默认不能超过1M

(11)numChildren - znode子节点数量

4.3 监听器原理(面试重点)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SnkqFrin-1638621332238)(/image-20211204195540188.png)]

4.4 选举机制(面试重点)

1.选举机制总原则:集群中的每台机器都参与投票,通过交换选票得到每台机器的最终得票,一旦出现得票数超过机器总数一半以上的数量,当前机器即为leader。

(1)半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。

(2)Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的。

(3)以一个简单的例子来说明整个选举的过程。

场景一:

​ 假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来看看会发生什么。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lpYJnyR0-1638621332239)(/image-20211204200713373.png)]

Zookeeper的选举机制

(1)服务器1启动,发起一次选举。服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成,服务器1状态保持为LOOKING;

(2)服务器2启动,再发起一次选举。服务器1和2分别投自己一票并交换选票信息:此时服务器1发现服务器2的ID比自己目前投票推举的(服务器1)大,更改选票为推举服务器2。此时服务器1票数0票,服务器2票数2票,没有半数以上结果,选举无法完成,服务器1,2状态保持LOOKING

(3)服务器3启动,发起一次选举。此时服务器1和2都会更改选票为服务器3。此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数,服务器3当选Leader。服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;

(4)服务器4启动,发起一次选举。此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。此时服务器4服从多数,更改选票信息为服务器3,并更改状态为FOLLOWING;

(5)服务器5启动,同4一样当小弟。

场景二:

​ 当前集群正在使用(有数据/没数据),leader突然宕机的情况。

当集群的leader挂掉,集群会重新选出一个leader,此时首先会比较每一台机器的czxid,

czxid最大的被选为leader。极端情况,czxid都相等的情况,那么就会直接比较myid。

一般情况下,Zookeeper适合安装奇数台服务器原因?

在ZK集群中,奇数台 和 偶数台(接近的台数)机器的容错能力是一样的,所以在考虑资源节省的情况下,我们推荐使用奇数台方案。

4.5 写数据流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w5at5f5c-1638621332239)(/image-20211204202327509.png)]

1)Client向Zookeeper的Server1上写数据,发送一个写请求

2)如果Server1不是Leader,那么Server1会把接收到的请求进一步转发给Leader,因为每个Zookeeper的Server里面有一个是Leader。这个Leader会将写请求广播给各个Server,比如Server1和Server2,各个Server会将该写请求加入待写队列,并向Leader发送成功信息

3)当Leader接收到半数以上Server的成功信息,说明该写操作可以执行。Leader会向各个Server发送提交信息,各个Server收到信息后会落实队列里的写请求,此时写成功。

4)Server1会进一步通知Client数据写成功了,这时就认为整个写操作成功。

5.企业问答题

一、请简述ZooKeeper的选举机制

选举机制总原则:集群中的每台机器都参与投票,通过交换选票得到每台机器的最终得票,一旦出现得票数超过机器总数一半以上的数量,当前机器即为leader。

场景一:

​ 假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动。

(1)服务器1启动,发起一次选举。服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成,服务器1状态保持为LOOKING;

(2)服务器2启动,再发起一次选举。服务器1和2分别投自己一票并交换选票信息:此时服务器1发现服务器2的ID比自己目前投票推举的(服务器1)大,更改选票为推举服务器2。此时服务器1票数0票,服务器2票数2票,没有半数以上结果,选举无法完成,服务器1,2状态保持LOOKING

(3)服务器3启动,发起一次选举。此时服务器1和2都会更改选票为服务器3。此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数,服务器3当选Leader。服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;

(4)服务器4启动,发起一次选举。此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。此时服务器4服从多数,更改选票信息为服务器3,并更改状态为FOLLOWING;

(5)服务器5启动,同4一样当小弟。

场景二:

​ 当前集群正在使用(有数据/没数据),leader突然宕机的情况。

当集群的leader挂掉,集群会重新选出一个leader,此时首先会比较每一台机器的czxid,

czxid最大的被选为leader。极端情况,czxid都相等的情况,那么就会直接比较myid。

二、ZooKeeper的监听原理是什么?

原理:

1)首先要有一个main()线程

2)在main线程中创建Zookeeper客户端,这时就会创建两个线程,一个负责网络连接通信(connect),一个负责监听(listener).

3)通过connect线程将注册的监听事件发送给Zookeeper。

4)在Zookeeper的注册监听列表将注册的监听事件添加到列表中

5)Zookeeper监听到有数据或路径变化,就会将这个消息发送给listener线程

6)listener线程内部调用了process()方法。

三、ZooKeeper的部署方式有哪几种?集群中的角色有哪些?集群最少需要几台机器?

(1)部署方式单机模式、集群模式

(2)角色:Leader和Follower

(3)集群最少需要机器数:3

四、ZooKeeper的常用命令

命令基本语法功能描述
help显示所有操作命令
ls path使用 ls 命令来查看当前znode的子节点-w 监听子节点变化-s 附加次级信息
create普通创建-s 含有序列-e 临时(重启或者超时消失)
get path获得节点的值-w 监听节点内容变化-s 附加次级信息
set设置节点的具体值
stat查看节点状态
delete删除节点
deleteall递归删除节点

五、ZK的写数据流程

1.客户端会向ZK集群中的一台机器Server1发送写数据请求

2.server1就收到请求后,马上会通知Leader有写数据的请求来了

3.Leader拿到请求后,进行广播,让集群每一台机器都准备要写数据

4.集群中的所有机器接收到Leader的广播后都回应一下leader

5.leader再次进行广播,开始写数据,其它机器就收到广播后开始写数据

6.数据成功写入后,回应leader,最后由leader来做整个事务提交

7.当数据成功写入后,由最初和客户端连接的Server1回应客户端数据写入成功。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值