ZooKeeper

一、引言


在分布式环境下,如果舍弃SpringCloud,使用其他的分布式框架,那么注册心中,配置集中管理,集群管理,分布式锁,队列的管理想单独实现怎么办。

二、Zookeeper介绍


Zookeeper本身是Hadoop生态圈的中的一个组件,Zookeeper强大的功能,在Java分布式架构中,也会频繁的使用到Zookeeper。

Zookeeper就是一个文件系统 + 监听通知机制

  • 注册中心

  • 配置中心

  • 集群管理中心(hadoop master 选举机制,hbase 选举)

  • 消息队列 (类似rabbitmq)

  • 分布式锁

三、Zookeeper安装


docker-compose.yml

version: "3.1"
services:
  zk:
   image: daocloud.io/daocloud/zookeeper:latest
   restart: always
   container_name: zk
   ports:
     - 2181:2181

启动

docker-compose  up

进入容器中的docker

docker exec -it zk bash


进入zk的控制台 

root@7c986e60ff1f:/opt/zookeeper# ./bin/zkCli.sh 

四、Zookeeper架构【重点

4.1 Zookeeper的架构图

  • 每一个节点都称为znode

  • 每一个znode中都可以存储数据

  • 节点名称是不允许重复的

Zookeeper的架构图

4.2 znode类型

四种Znode

  • 持久节点:永久的保存在你的Zookeeper

  • 持久有序节点:永久的保存在你的Zookeeper,他会给节点添加一个有序的序号。 /xx -> /xx0000001

  • 临时节点:当存储的客户端和Zookeeper服务断开连接时,这个临时节点自动删除

  • 临时有序节点:当存储的客户端和Zookeeper服务断开连接时,这个临时节点自动删除,他会给节点添加一个有序的序号。 /xx -> /xx0000001

4.3 Zookeeper的监听通知机制

客户端可以去监听Zookeeper中的Znode节点。

Znode改变时,会通知监听当前Znode的客户端

监听通知机制

五、Zookeeper常用命令


Zookeeper针对增删改查的常用命令

创建节点

create [-s] [-e] znode名称

znode数据

# -s:sequence,有序节点

# -e:ephemeral,临时节点

create /java hello-java

 创建子节点

create /java/spring hello-spring

创建有序节点

create -s /html hello-html

 创建临时节点 client断开时删除

create -e /php hello-php  

 创建临时有序节点

create -s -e /js hello-js

查看当前节点下全部子节点

ls 节点名称

ls /



# 查询当前节点下的数据
get 节点名称
# 例子 get /java


# 修改节点值
set znode名称 新数据
set /java hello-world-java


 ​

# 删除节点
delete znode名称    # 没有子节点的znode
delete /node2/node1



rmr znode名称      # 删除当前节点和全部的子节点
rmr /node2

 

六、Zookeeper集群【重点


6.1 Zookeeper集群架构图

集群架构图

6.2 Zookeeper集群中节点的角色

  • Leader:Master主节点

  • Follower (默认的从节点):从节点,参与选举全新的Leader

  • Observer:从节点,不参与投票

  • Looking:正在找Leader节点

6.3 Zookeeper选举机制

(1)Zookeeper集群中只有超过半数以上的服务器启动,集群才能正常工作;

(2)在集群正常工作之前,myid小的服务器给myid大的服务器投票,直到集群正常工作,选出Leader;

(3)选出Leader之后,之前的服务器状态由Looking改变为Following,以后的服务器都是Follower。

参考:

Zookeeper的选举机制原理(图文深度讲解)_攻城狮Kevin-CSDN博客_zk选举机制

6.4 搭建Zookeeper集群

yml文件

创建新的文件夹

version: "3.1"
services:
  zk1:
    image: zookeeper
    restart: always
    container_name: zk1
    ports:
      - 2181:2181
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181
  zk2:
    image: zookeeper
    restart: always
    container_name: zk2
    ports:
      - 2182:2181
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181
  zk3:
    image: zookeeper
    restart: always
    container_name: zk3
    ports:
      - 2183:2181
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181

端口说明

1、2181:对cline端提供服务
​
2、3888:选举leader使用
​
3、2888:集群内机器通讯使用(Leader监听此端口)

运行,注意先将之前的zk关闭,运行之后可以看到bin文件中有 zkServer.sh

输入命令查看在集群中扮演的角色

./zkServer.sh status

zk1

 zk2

zk3

可以看到zk3为leader

这是在zk3中写入节点 /java 赋值为 hello-java

在zk1和zk2中都可以获取到值 

此时将zk3关闭

查看zk1和zk2的状态

 可以看到zk1仍未follower

zk2以及转变为leader

 

重新启动zk3并查看状态,发现此时zk3为follower

七、Java操作Zookeeper


7.1 Java连接Zookeeper

创建Maven工程

导入依赖

<dependencies>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.6.0</version>
    </dependency>
​
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>4.0.1</version>
    </dependency>
​
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

编写连接Zookeeper集群的工具类

public class ZkUtil {
    public static CuratorFramework cf(){
        ExponentialBackoffRetry exponentialBackoffRetry = new ExponentialBackoffRetry(3000, 2);
        CuratorFramework cf = CuratorFrameworkFactory
.builder()
.connectString("8.130.166.101:2181,8.130.166.101:2182,8.130.166.101:2183")
.retryPolicy(exponentialBackoffRetry).build();
        cf.start();
        return cf;
    }
}

7.2 Java操作Znode节点

查询

public class ZkTest {
    CuratorFramework curatorFramework = ZkUtil.cf();
    //获取子节点
    @Test
    public void getChildren() throws Exception {
        List<String> list = curatorFramework.getChildren().forPath("/");

        for (String s : list) {
            System.out.println(s);
        }
    }
    //获取节点数据
    @Test
    public void getData() throws Exception {
        byte[] bytes = curatorFramework.getData().forPath("/java");
        System.out.println("data:"+new String(bytes,"utf-8"));
    }
   

}

 

添加

 //添加节点
    @Test
    public void addNode() throws Exception {
        curatorFramework.create().withMode(CreateMode.PERSISTENT).forPath("/html","css".getBytes());
    }

修改

//修改节点数据
    @Test
    public void update() throws Exception {
        Stat stat = curatorFramework.setData().forPath("/html", "javascripe".getBytes());
        System.out.println(stat);
    }

删除

 //删除节点
    @Test
    public void delete() throws Exception {
        curatorFramework.delete().deletingChildrenIfNeeded().forPath("/html");
    }

查看znode的状态

//查看节点状态
    @Test
    public void check() throws Exception {
        Stat stat = curatorFramework.checkExists().forPath("/java");
        System.out.println(stat);
    }

7.3 监听通知机制

实现方式

public class Listener {

    CuratorFramework curatorFramework = ZkUtil.cf();
    @Test
    public void listener() throws Exception {
        NodeCache nodeCache = new NodeCache(curatorFramework, "/java");
        nodeCache.start();
        nodeCache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                byte[] data = nodeCache.getCurrentData().getData();
                Stat stat = nodeCache.getCurrentData().getStat();
                String path = nodeCache.getCurrentData().getPath();
                System.out.println("data:"+new String(data,"utf-8")+"-----stat:"
                                    +stat+"-----path:"+path );
            }
        });
        System.out.println("开始监听");
        System.in.read();
    }
}

在zk中更改数据 可以看到控制台更新数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇智波波奶茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值