一.简介

在这里插入图片描述

二.部署

1.单机部署

  • 下载:3.5.5版本后下载 -bin文件 :apache-zookeeper-3.5.9-bin.tar.gz 2021-01-15 03:46 9.2M
  • 进入配置文件夹 cd conf
  • 复制配置文件cp zoo_sample.cfg zoo.cfg
  • 修改配置文件
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/software/server/apache-zookeeper-3.5.9-bin/data
clientPort=2181
#会话超时时间
#minSessionTimeout=4000
#maxSessionTimeout=40000
  • 启动
    cd bin
    sh zkServer.sh start
    sh zkServer.sh status
  • 停止
    sh zkServer.sh stop
  • 打开客户端
    sh zkCli.sh
  • 查看根节点下的子节点(Znode维系在内存和磁盘中)
    ls /
  • 根节点下创建子节点(必须存储配置信息或节点描述)
    create /log 'log servers'
  • 子节点下创建子节点(必须存储配置信息或节点描述)
    create /log/log01 ''
  • 删除节点(要求没有子节点)
    delete /music
  • 删除节点
    rmr /music
  • 查看节点详情
    get /picture
  • 修改数据
    set /picture 'ps'

2.分布式部署

  • 下载:3.5.5版本后下载 -bin文件 :apache-zookeeper-3.5.9-bin.tar.gz 2021-01-15 03:46 9.2M
  • 进入配置文件夹 cd conf
  • 复制配置文件cp zoo_sample.cfg zoo.cfg
  • 修改配置文件
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/software/server/apache-zookeeper-3.5.9-bin/data
clientPort=2181
#2888选举端口,3888原子广播端口
server.1=172.18.29.152:2888:3888
server.2=172.18.29.150:2888:3888
server.3=172.18.29.153:2888:3888
  • 创建mkdir /usr/local/software/server/apache-zookeeper-3.5.9-bin/data
  • 进入cd /usr/local/software/server/apache-zookeeper-3.5.9-bin/data
  • 分别配置 vim myid
#server.1 其它文件以此类推
1
  • 将内容传到其它节点
    scp -r apache-zookeeper-3.5.9-bin root@172.18.29.150:/usr/local/software/server/
    scp -r apache-zookeeper-3.5.9-bin root@172.18.29.153:/usr/local/software/server/
  • 再修改myid
  • 通过sh zkServer.sh status查看状态

三.基本属性

1.节点详细信息

cZxid: 创建节点的事务id(全局递增,增删改公用一个id)
ctime: 创建节点的时间
mZxid: 修改节点的事务id(全局递增,增删改公用一个id)
mtime: 修改节点的时间
pZxid: 子节点的增删事务id(全局递增,增删改公用一个id)
cversion: 子节点的增删次数
dataversion: 当前节点数据的修改次数
aclversion: 当前节点的权限修改次数
ephemeralOwner: 标记当前节点是否是临时节点(默认是0,临时节点为sessionID)
dataLength: 数据的字节个数
numChildren: 子节点个数

2.节点类型

  • 非顺序节点:(默认)
    持久节点(默认) PERSISTENT
    临时节点 create -e /video ''(不能有子节点,客户端退出消失) EPHEMERAL
  • 顺序节点:create -s /log/l ''
    持久节点(默认)PERSISTENT_SEQUENCIAL
    临时节点 create -e /video ''(不能有子节点,客户端退出消失) EPHEMERAL_SEQUENCIAL

四.API基本操作

  • 引入依赖:
<properties>
        <java.version>11</java.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.5.9</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>

    </dependencies>
  • 单元测试
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class ZookeeperDemo1 {

    private ZooKeeper zk;

    /**
     * 创建连接
     * @throws IOException
     * @throws InterruptedException
     */
    @Before
    public void connect() throws IOException, InterruptedException {
        //connectString - 连接地址+端口号
        //sessionTimeout - 会话超时时间(多长时间连不上就断开),默认单位是毫秒4000~40000之间
        //watcher - 监控者,判断到底连上没有
        CountDownLatch cd1 = new CountDownLatch(1);
        zk = new ZooKeeper("39.97.169.72:2181", 5000, watchedEvent -> {
            if(watchedEvent.getState() == Watcher.Event.KeeperState.SyncConnected){
                System.out.println("连接成功~");
                cd1.countDown();
            }
        });
        cd1.await();
    }

    /**
     * 创建节点
     */
    @Test
    public void createNode() throws KeeperException, InterruptedException {
        //path:创建的节点路径
        //data:节点数据
        //acl:权限
        //createMode:节点类型
        String nameNode = zk.create(
                "/video","video server".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.PERSISTENT_SEQUENTIAL);
        System.out.println("持久节点名称:"+nameNode);
    }

    /**
     * 删除节点
     */
    @Test
    public void deleteNode() throws KeeperException, InterruptedException {
        //version - 数据版本 :dataversion
        zk.delete("/video0000000004",0);
        //version= -1 强制删除
        zk.delete("/video0000000004",-1);
    }

    /**
     * 获得所有子节点
     */
    @Test
    public void getChildrenNode() throws KeeperException, InterruptedException {
        List<String> children = zk.getChildren("/", null);
        for(String c:children){
            System.out.println(c);
        }
    }

    /**
     * 判断节点是否存在
     */
    @Test
    public void exists() throws KeeperException, InterruptedException {
        //返回节点信息 节点不存在返回null 否则返回信息
        Stat s = getNodeMessage();
        if(s==null){
            System.out.println("节点不存在");
        }
        System.out.println("节点存在 "+ s.toString());
    }

    /**
     * 获得节点详细信息
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    public Stat getNodeMessage() throws KeeperException, InterruptedException {
        Stat stat = zk.exists("/log",null);
        return stat;
    }

    /**
     * 获取节点数据
     */
    @Test
    public void getData() throws KeeperException, InterruptedException {
        byte[] data = zk.getData("/log", null, getNodeMessage());
        System.out.println(new String(data));
    }

    /**
     * 修改(更新)节点数据
     */
    public void setData() throws KeeperException, InterruptedException {
        //返回值是节点信息
        Stat stat = zk.setData("/log", "log server".getBytes(), -1);
    }


}

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.notification.RunListener;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class ZookeeperDemo2 {

    private ZooKeeper zk;

    /**
     * 创建连接
     * @throws IOException
     * @throws InterruptedException
     */
    @Before
    public void connect() throws IOException, InterruptedException {
        //connectString - 连接地址+端口号
        //sessionTimeout - 会话超时时间(多长时间连不上就断开),默认单位是毫秒4000~40000之间
        //watcher - 监控者,判断到底连上没有
        CountDownLatch cd1 = new CountDownLatch(1);
        zk = new ZooKeeper("39.97.169.72:2181", 5000, watchedEvent -> {
            if(watchedEvent.getState() == Watcher.Event.KeeperState.SyncConnected){
                System.out.println("连接成功~");
                cd1.countDown();
            }
        });
        cd1.await();
    }

    /**
     * 监控当前节点数据是否发生变化
     */
    @Test
    public void nodeDataChanged() throws KeeperException, InterruptedException {
        while (true){
            CountDownLatch cdl1 = new CountDownLatch(1);
            zk.getData("/log", new Watcher() {
                //将数据的变化封装成一个事件进行传递
                @Override
                public void process(WatchedEvent watchedEvent) {
                    if(watchedEvent.getType() == Event.EventType.NodeDataChanged){
                        System.out.println("节点数据更新~");
                        cdl1.countDown();
                    }
                }
            }, null);
            cdl1.await();
        }
    }

    /**
     * 监控子节点的数据是否发生变化
     */
    @Test
    public void childNodeDataChanged() throws KeeperException, InterruptedException {
        while (true) {
            CountDownLatch cdl1 = new CountDownLatch(1);
            zk.getChildren("/log", new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    if (watchedEvent.getType() == Event.EventType.NodeChildrenChanged) {
                        System.out.println("子节点发生变化~~~");
                        cdl1.countDown();
                    }
                }
            });
            cdl1.await();
        }
    }

    /**
     * 监控一个节点的增删变化
     */
    @Test
    public void nodeChanged() throws KeeperException, InterruptedException {
        while (true){
        CountDownLatch cdl1 = new CountDownLatch(1);
        zk.exists("/video", new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                if(watchedEvent.getType() == Event.EventType.NodeCreated){
                    System.out.println("新增这个节点");
                }else {
                    System.out.println("删除这个节点");
                }
                cdl1.countDown();
            }
        });
        cdl1.await();
        }
    }
}

五.选举机制

1.过程

  • 每个节点会寻找当前节点的最大事务id
  • 每个节点都会推荐自己为leader,同时将节点信息发给其它节点,进行比较,

2.选举信息

  • 最大事务 - Zxid
  • 选举编号 - myid
  • 逻辑时钟值 - 保证选举在同一轮次上(会将过多轮比较)

3.比较原则

  • 先比较最大事务id,选更大的
  • 其次比较myid,选更大的
  • 当一个节点胜过一半及以上的节点的时候,那么这个节点就会成为leader - 选举过半性(原先总数的过半)
  • 当leader已经存在,后续都是follower
  • 当满足过半存活(原先总数的过半)才会进行选举(防止脑裂)

4.节点状态

looking/voting - 选举状态
follower - 追随者
leader - 领导者
observer - 观察者

六,ZAB协议原子广播

1.过程

  • leader将写操作记录道本地日志log.xxx,记录成功发送道队列
  • follower会执行队列中的操作(写入本地日志)
  • leader如果收到半数及以上的follower的成功信号,那么leader就会命令每个follower执行这个操作
  • leader没有收到半数的follower的成功信号,那么leader就会命令每一个follower删除刚才的操作

2.目的

  • 保证集群中的所有节点的数据一致性(C)

3.崩溃恢复

每个leader被选举出来之后,都会被分配一个全局递增的编号-epochid,分发给每一个follower,若出现脑裂情况,则自动kill掉epochid小的leader并将其转化成follower,保证集群中只有一个leader。

  • epochid存储在version文件夹中
  • cZxid由64位的2禁止数字组成
  • epochid == 高32位
  • 真正的事务id == 低32位

七.查看二进制文件日志

  • 每更换一次leader,就会产生一个新的log以及snapshot文件
cd lib
cp zookeeper-3.5.9.jar /usr/local/software/server/apache-zookeeper-3.5.9-bin/data/version-2/
cp slf4j-api-1.7.25.jar /usr/local/software/server/apache-zookeeper-3.5.9-bin/data/version-2/
cp zookeeper-jute-3.5.9.jar /usr/local/software/server/apache-zookeeper-3.5.9-bin/data/version-2/

cd /usr/local/software/server/apache-zookeeper-3.5.9-bin/data/version-2/
#查看日志:记录操作
java -cp .:zookeeper-3.5.9.jar:slf4j-api-1.7.25.jar:zookeeper-jute-3.5.9.jar org.apache.zookeeper.server.LogFormatter log.200000001
#查看快照:记录节点信息
java -cp .:zookeeper-3.5.9.jar:slf4j-api-1.7.25.jar:zookeeper-jute-3.5.9.jar org.apache.zookeeper.server.SnapshotFormatter snapshot.100000000

在这里插入图片描述

八.观察者Observer

1.特点

  • 不参与投票也不选举,只干活
  • 宕机个数不影响服务

2.配置

  • 修改配置文件vim zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/software/server/apache-zookeeper-3.5.9-bin/data
clientPort=2181
#2888选举端口,3888原子广播端口
peerType=observer
server.1=172.18.29.152:2888:3888:observer
server.2=172.18.29.150:2888:3888
server.3=172.18.29.153:2888:3888

九.远程操作

  • 下载nc
    yum install -y nc
  • 修改启动文件
    vim zkServer.sh
  • 添加内容
ZOOMAIN="-Dzookeeper.4lw.commands.whitelist=* ${ZOOMAIN}"

在这里插入图片描述

  • 查看其它节点的状态
echo stat | nc 172.18.29.150 2181
  • 查看其它节点是否存活
echo ruok | nc 172.18.29.150 2181
#返回imok表存活
imok
  • 查看其它节点配置信息
echo conf | nc 172.18.29.150 2181
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐