zookeeper

zookeeper

概述:

​ ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

ZooKeeper包含一个简单的原语集,提供Java和C的接口。

ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在$zookeeper_home\src\recipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本。

Zookeeper端口:

zookeeper默认端口号:

  1. 代码访问client的端口号: 2181
  2. leader和flower通信的端口号: 2888
  3. 选举leader时通信的端口号: 3888
  4. 其他服务与监控中心通信端口: 7070

Zookeeper工作机制:

​ zookeeper从设计模式角度:是一个基于观察者模式设计的分布式管理框架,他负责管理大家都关心的数据,然后接收观察者的注册,一旦数据发生变化,zookeeper就通知已经在zookeeer上注册的观察者作出相应的反应。

在这里插入图片描述

zookeeper=文件系统+通知机制

zookeeper特点:

在这里插入图片描述

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

  1. zookeeper:一个领导者(leader),多个跟随者(follower)组成的集群。
  2. 集群中只要有半数以上节点存活,zookeeper集群就能正常运行
  3. 全局数据一致性,每个server保存一份相同的数据,client无论连接到那个server,数据都是一致的。
  4. 更新请求顺序进行,来自同一个client的更新请求按发送顺序以依次进行
  5. 数据更新原子性,一次数据更新要么成功要么失败。
  6. 实时性,在一定时间范围内,client能读取到最新数据

zookeeper数据结构:

Zookeeper 的数据模型图:
在这里插入图片描述

​ 在 Zookeeper 中,每一个数据节点都是一个 ZNode,每个节点都默认只能存储最大1MB数据,每个Znode都可以通过其路径唯一标识上图根目录下有两个节点,分别是:app1 和 app2,其中 app1 下面又有三个子节点。那么我们来看看 ZNode 数据结构到底是什么样子的呢。首先我们来了解 ZNode 的类型。

每一个节点称为一个ZNode,每一个ZNode维持一个数据结构:

  • Version number − 版本号,当和该znode节点关联的数据发生变化时,版本号会自增1。
  • Action Control List (ACL) − 访问控制列表,znode的访问控制机制,它控制znode的所有读写操作。
  • Timestamp − znode创建时的时间戳,精确到毫秒。
  • Data length − znode节点存储数据的长度,最大1MB

zookeeper节点类型:

Znode有两种类型:
  • 短暂(ephemeral):客户端和服务器端断开连接后,创建的节点自己删除

  • 持久(persistent):客户端和服务器端断开连接后,创建的节点不删除

Znode有四种形式的目录节点(默认是persistent ):
  1. 持久化目录节点(PERSISTENT)

    1. 客户端与zookeeper断开连接后,该节点依旧存在
    2. 持久节点就是节点被创建后会一直存在服务器,直到删除操作主动清除,这种节点也是最常见的类型。
  2. 持久化顺序编号目录节点(PERSISTENT_SEQUENTIAL)

    1. 客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号

    2. 持久顺序节点就是有顺序的持久节点,节点特性和持久节点是一样的,只是额外特性表现在顺序上。顺序特性实质是在创建节点的时候,会在节点名后面加上一个数字后缀,来表示其顺序。

    说明:顺序号是一个单调递增的计数器,由父节点维护。

    注意:在分布式系统中,顺序号可以被用于为所有事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序.

  3. 临时目录节点(EPHEMERAL)

    1. 客户端与zookeeper断开连接后,该节点被删除
    2. 临时节点就是会被自动清理掉的节点,它的生命周期和客户端会话绑在一起,客户端会话结束,节点会被删除掉。与持久性节点不同的是,临时节点不能创建子节点。
  4. 临时顺序编号目录节点(EPHEMERAL_SEQUENTIAL)

    1. 客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
    2. 临时顺序节点就是有顺序的临时节点,和持久顺序节点相同,在其创建的时候会在名字后面加上数字后缀。

zookeeper应用场景:

一致性配置管理

​ 我们在开发的时候,有时候需要获取一些公共的配置,比如数据库连接信息等,并且偶然可能需要更新配置。如果我们的服务器有N多台的话,那修改起来会特别的麻烦,并且还需要重新启动。这里Zookeeper就可以很方便的实现类似的功能。

  • 将公共的配置存放在Zookeeper的节点中

  • 应用程序可以连接到Zookeeper中并对Zookeeper中配置节点进行读取或者修改(对于写操作可以进行权限验证设置)

在这里插入图片描述

注意:应用程序注册的watcher每次只能触发一次,当获取完消息之后需要再注册一次watcher

SpringCloud配置中心

统一命名服务(服务注册中心):

​ 命名服务也是分布式系统中比较常见的一类场景。在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。被命名的实体通常可以是集群中的机器,提供的服务地址,远程对象等等——这些我们都可以统称他们为名字(Name)。其中较为常见的就是一些分布式服务框架中的服务地址列表。通过调用ZK提供的创建节点的API,能够很容易创建一个全局唯一的path,这个path就可以作为一个名称。

阿里巴巴集团开源的分布式服务框架Dubbo中使用ZooKeeper来作为其命名服务,维护全局的服务地址列表,点击这里查看Dubbo开源项目。在Dubbo实现中:

服务提供者在启动的时候,向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入自己的URL地址,这个操作就完成了服务的发布。

服务消费者启动的时候,订阅/dubbo/ s e r v i c e N a m e / p r o v i d e r s 目 录 下 的 提 供 者 U R L 地 址 , 并 向 / d u b b o / {serviceName}/providers目录下的提供者URL地址, 并向/dubbo/ serviceName/providersURL/dubbo/{serviceName} /consumers目录下写入自己的URL地址

注意:所有向ZK上注册的地址都是临时节点,这样就能够保证服务提供者和消费者能够自动感应资源的变化。

另外,Dubbo还有针对服务粒度的监控,方法是订阅/dubbo/${serviceName}目录下所有提供者和消费者的信息。

zoookepper统一集群管理:

在这里插入图片描述

  • 分布式环境中实时掌握每个节点的状态是必要的。
    • 可根据节点实时状态作出一些调整。
  • zookeeper可实现实时监控节点状态的变化.
    • 可将节点信息写入zookeeper上的ZNode
    • 监听这个ZNode可以获取它的实时状态

zookeeper软负载均衡

​ ZooKeeper会维护一个树形的数据结构,类似于Windows资源管理器目录,其中EPHEMERAL类型的节点会随着创建它的客户端断开而被删除,利用这个特性很容易实现软负载均衡。

​ 基本原理是,每个应用的Server启动时创建一个EPHEMERAL(临时)节点,应用客户端通过读取节点列表获得可用服务器列表,并订阅节点事件,有Server宕机断开时触发事件,客户端监测到后把该Server从可用列表中删除

  • 一、获取服务器列表,通过随机数,客户端随机获取一台服务器进行访问
  • 二、采用计数器方式,连接上加一,断开减一,获取计数最少的连接

zookeeper下载:

官网下载地址:

在这里插入图片描述

在这里插入图片描述

安装:

将下载安装包上传至linux,安装zookeeper需要jdk,通过java javac java -version 命令查看是否安装jdk

java 
javac 
java -version

jdk安装教程:

解压:

tar -zxvf zookeeper-3.4.14.tar.gz

配置:

cd zookeeper-3.4.14/conf/
cp zoo_sample.cfg zoo.cfg
vim zoo.cfg 

在这里插入图片描述

将dataDir修改为自己定义的信息存储路径:

在这里插入图片描述

创建data目录:

mkdir data

在这里插入图片描述

启动:

#进入bin目录
cd bin
#启动zk
./zkServer.sh start
#查看进程
jsp

在这里插入图片描述

#查看状态
./zkServer.sh status

在这里插入图片描述

Mode:standalone 单击模式

退出服务:

#退出服务
./zkServer.sh stop

启动客户端:

 #启动客户端
 ./zkCli.sh 
 
 #查看节点 注意:ls 空格 /
ls /

#退出
quit

在这里插入图片描述

zookeeper配置参数:

tickTime 心跳时间默认两秒,为了确保client-server连接存在的,以毫秒为单位,最小超时时间为两个心跳时间。

initLimit	多少个tickTime内,允许其他server连接并初始化数据,如果zooKeeper管理的数据较大,则应相应增大这个值。 默认10就是10*tickTime(10*2000ms == 2s)

syncLimit	多少个tickTime内,允许follower同步,如果follower落后太多,则会被丢弃。默认5 ,(5*tickTime==5*2000ms)

dataDir	用于存放内存数据库快照的文件夹,同时用于集群的myid文件也存在这个文件夹里。

dataLogDir	用于单独设置transaction log的目录,transaction log分离可以避免和普通log还有快照的竞争。

clientPort	客户端监听端口。(客户端链接服务端端口)

globalOutstandingLimit		client请求队列的最大长度,防止内存溢出,默认值为1000。

preAllocSize	预分配的Transaction log空间block为proAllocSize KB,默认block为64M,一般不需要更改,除非snapshot过于频繁。

snapCount	在snapCount个snapshot后写一次transaction log,默认值是100,000。

traceFile	用于记录请求的log,打开会影响性能,用于debug,最好不要定义。

maxClientCnxns	最大并发客户端数,用于防止DOS的,默认值是10,设置为0是不加限制。

clientPortBindAddress	可以设置指定的client ip以及端口,不设置的话等于ANY:clientPort

minSessionTimeout	 最小的客户端session超时时间,默认值为2个tickTime,单位是毫秒

maxSessionTimeout	最大的客户端session超时时间,默认值为20个tickTime,单位是毫秒

electionAlg	
	用于选举的实现的参数:
  ①0:为以原始的基于UDP的方式协作
  ②1:为不进行用户验证的基于UDP的快速选举
  ③2:为进行用户验证的基于UDP的快速选举
  ④3:为基于TCP的快速选举,默认值为3
  
  
leaderServes		leader是否接受客户端连接。默认值为yes。leader负责协调更新。当更新吞吐量远高于读取吞吐量时,可以设置为不接受客户端连接,以便leader可以专注于同步协调工作。

server.x=[hostname]:nnnnn[:nnnnn]
	配置集群里面的主机信息,其中:
  ①server.x:server.x的x要写在myid文件中,决定当前机器的id,
  ②第一个port用于连接leader,
  ③第二个用于leader选举。
  ④如果electionAlg为0,则不需要第二个port。
  ⑤hostname也可以填ip。
  
group.x=nnnnn[:nnnnn]		 分组信息,表明哪个组有哪些节点,例如group.1=1:2:3 group.2=4:5:6 group.3=7:8:9。

weight.x=nnnnn		权重信息,表明哪个结点的权重是多少,例如weight.1=1 weight.2=1 weight.3=1。
	

zookeeper选举机制(重点):

  1. 半数机制:集群中半数以上机器存活,集群可用。所以zookeeper适合安装奇数台服务器。
  2. zookeeper虽然在配置文件中并没有指定Masterslaver。但是Zookeeper在工作时是有一个Leader和多个Follower,Leader是通过内部选举机制临时产生的。
    3.在这里插入图片描述

zookeeper提供了三种方式:

  • LeaderElection
  • AuthFastLeaderElection
  • FastLeaderElection (最新默认)

默认的算法是FastLeaderElection,所以这篇主要分析它的选举机制。

选举流程简述:

​ 目前有5台服务器,每台服务器均没有数据,它们的编号分别是1,2,3,4,5,按编号依次启动,它们的选择举过程如下:

  • 服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于Looking(选举状态)。
  • 服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是LOOKING。
  • 服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。
  • 服务器4启动,给自己投票,同时与之前启动的服务器1,2,3交换信息,尽管服务器4的编号大,但之前服务器3已经胜出,所以服务器4只能成为小弟。
  • 服务器5启动,后面的逻辑同服务器4成为小弟。

选择机制中的概念:

1、Serverid:服务器ID

​ 比如有三台服务器,编号分别是1,2,3。

编号越大在选择算法中的权重越大。

2、Zxid:数据ID

​ 服务器中存放的最大数据ID.

值越大说明数据越新,在选举算法中数据越新权重越大。

3、Epoch:逻辑时钟

​ 或者叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加,然后与接收到的其它服务器返回的投票信息中的数值相比,根据不同的值做出不同的判断。

4、Server状态:选举状态

  • LOOKING,竞选状态。
  • FOLLOWING,随从状态,同步leader状态,参与投票。
  • OBSERVING,观察状态,同步leader状态,不参与投票。
  • LEADING,领导者状态

选举消息内容

在投票完成后,需要将投票信息发送给集群中的所有服务器,它包含如下内容。

  • 服务器ID
  • 数据ID
  • 逻辑时钟
  • 选举状态

Zookeeper分布式集群安装:

方式一:

  • ​ 将第一台服务器安装配置好的zookeeper远程拷贝至多台服务器并修改拷贝后的配置
	scp -r /home/administrator/test/ root@192.168.1.100:/root/

方式二:

1.在三台linux服务器上安装zookeeper

2.修改zoo.cfg:

# 配置三台的ip,广播端口(用于通讯)和选举端口
server.1=192.168.200.140:2888:3888
server.2=192.168.200.150:2888:3888
server.3=192.168.200.160:2888:3888

3.在dataDir目录下新建myid

在这里插入图片描述

echo 1 > myid

​ 每个服务器创建myid时,对应zoo.cfg配置文件汇中的server.数子.如:192.168.200.140 创建:

echo 1 > myid

​ 192.168.200.150创建时,以此类推:

echo 2 > myid

4.在三台服务器启动zookeeper:

在这里插入图片描述

查看zoookeeper日志:

在那个目录启动日志文件就在哪里,一般在bin目录

在这里插入图片描述

出现此错误则关闭linux防火墙!

关闭CentOS 7.0防火墙

CentOS 7.0默认使用的是firewall作为防火墙:

#查看防火墙状态
firewall-cmd --state

#停止firewall
systemctl stop firewalld.service

#禁止firewall开机启动
systemctl disable firewalld.service 

出现java.net.ConnectException: 拒绝连接 (Connection refused)

等待其他两台服务启动后在查看状态,出现此错误因其他服务还未启动。

在这里插入图片描述

等待三台服务启动后查看状态:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

出现一个Leader和两个Follower则成功!

zookeeper客户端命令行操作:

命令基本语法功能描述
help显示所有命令操作
ls path [watch]使用ls命令来查看当前ZNode中所包含的内容
ls2 path [watch]查看当前节点数据,并能看到更新次数等数据
create普通创建 -s 含序列 -e 临时(重启或者超时消失)
get path [watch]获得节点的值
set设置节点的具体值
stat查看节点状态
delete删除节点
rmr递归删除节点
#查看节点
ls /

#查看节点详细信息
ls2 /

#创建节点
create /sanguo "jinlian"

#创建节点的子节点
create /sanguo/shuguo "liubei"

#获取节点数据
get /sanguo

#获取节点子节点数据
get /sanguo/shuguo

#查看节点状态
stat /sanguo

#删除节点
delete /sanguo

#递归删除
rmr /sanguo

#创建临时节点 (在退出后消失)
create -e /sanguo/wuguo "zhouyu"

#创建持久顺序节点
create -s /sanguo/weiguo "caocao"

#设置节点的值
set /sanguo/shuguo "liushan"

节点的值监听变化:

#监听三国值的变化
get /sanguo watch

在二号服务器监听三号的值变化:

在这里插入图片描述

在一号服务器修改三号的值:

在这里插入图片描述

当三国值修改后二号服务器的变化:

在这里插入图片描述

在这里插入图片描述

==注意:==watch只能使用一次,在监听到数据变化后需重新监听。

Stat结构体:

在这里插入图片描述

  1. cZxid:创建节点的事务zxid
    1. 每次修改Zookeeper状态都会收到一个Zxid形式的时间戳,也就是Zookeeper事务ID
    2. 事务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如果是临时节点,这个是ZNode拥有者的Session Id ,如果不是临时节点是0*0
  10. dataLength: ZNode的数据长度
  11. ==numChildren:==ZNode子节点数量

Zookeeper监听原理(重点):

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

  1. 首先有一个main()线程
  2. 在main线程中创建Zookeeper客户端,会创建两个线程,connect负责网络连接通信,listener负责监听
  3. 通过connect线程将注册的监听事件发送给Zookeeper
  4. 在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中
  5. Zookeeper监听到有数据或路径变化,就会将这个消息发送给listener线程
  6. listener线程内部调用了process()方法

常见的监听:

  • 监听节点数据的变化:

    • get path [watch]
      
  • 监听节点数量的变化

    • ls path [watch]
      

Zookeeper集群写数据流程:

在这里插入图片描述

JavaClientAPI:

  • 创建普通maven项目:

  • 添加依赖

    • ==注意:==zookeeper依赖版本为3.4.6,我使用3.4.14程序有问题。
 <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.13.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>

    </dependencies>

添加log4j日志配置:

### 设置###
log4j.rootLogger = debug,stdout,D,E

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

常用命令API:

package com.cwh.zookeeper;

import lombok.SneakyThrows;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName : ZookeeperTest
 * @Description :
 * @Author : cuiweihua
 * @Date: 2020-09-08 10:05
 */
public class ZookeeperTest {

    /**
     *  此处ip:端口也可,只写ip也可  
     */
    private String connectionString = "192.168.138.128:2181,192.168.138.130:2181,192.168.138.131:2181";
    private Integer sessionTime = 2000;
    private ZooKeeper zkClient = null;
    private Logger logger = LoggerFactory.getLogger(ZookeeperTest.class);

    @SneakyThrows
    @Before
    public void init(){
        zkClient = new ZooKeeper(connectionString, sessionTime, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                try {
                    logger.info("监听到节点的变化");
                    //重新注册监听 因为watch是一次性的
                    System.out.println("\n");
                    zkClient.getChildren("/", true).forEach(System.out::println);
                    System.out.println("\n");
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        },false);
        logger.info("zkCLient 初始化成功!");

    }

    /**
     * 创建节点
     */
    @Test
    public void create(){
        logger.info("开始创建节点");
        String path = null;
        try {
            path = zkClient.create("/test2", "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            logger.info("节点创建完毕"+path);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取子节点并监控
     */
    @Test
    public void getZNodeAndWatch() throws KeeperException, InterruptedException {
        //获取子节点不监听
        /*zkClient.getChildren("/",false).forEach(System.out::println);*/
        //获取子节点并监听
        zkClient.getChildren("/", true);

        //想要持续监听,需要使线程保持运行
        while (true){
            TimeUnit.SECONDS.sleep(2);
        }
    }

    /**
     * 查看节点是否存在
     */
    @Test
    public void exist() throws KeeperException, InterruptedException {
        Stat exists = zkClient.exists("/sanguo", false);
        System.out.println("节点信息:"+exists);
    }

    @SneakyThrows
    @After
    public void close(){
        zkClient.close();
        logger.info("zkClient 关闭连接");
    }
}

实现服务器动态上下线案例:

服务端:

package com.cwh.zookeeper;

import org.apache.zookeeper.*;

import java.io.IOException;

/**
 * @ClassName : Server01
 * @Description :
 * @Author : cuiweihua
 * @Date: 2020-09-08 16:09
 */
public class Server01 {
    private static final String connectionString = "192.168.138.128:2181,192.168.138.130:2181,192.168.138.131:2181";
    private static final Integer sessionTime = 2000;
    private static ZooKeeper zkClient = null;

    public static void main(String[] args) throws KeeperException, InterruptedException {
        //获取连接
        getConnection();
        //注册节点
        register("cwh");
        //业务
        sleep();


    }

    private static void sleep() {
        try {
            Thread.sleep(Long.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void register(String arg) throws KeeperException, InterruptedException {
        zkClient.create("/servers/server01",arg.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
    }

    private static void getConnection() {
        try {
            zkClient = new ZooKeeper(connectionString, sessionTime, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {

                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}

客户端:

package com.cwh.zookeeper;

import org.apache.zookeeper.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName : Client01
 * @Description :
 * @Author : cuiweihua
 * @Date: 2020-09-08 16:09
 */
public class Client01 {
    private static final String connectionString = "192.168.138.128:2181,192.168.138.130:2181,192.168.138.131:2181";
    private static final Integer sessionTime = 2000;
    private static ZooKeeper zkClient = null;

    public static void main(String[] args) throws KeeperException, InterruptedException {
        //获取连接
        getConnection();
        //客户端监听
        getChlidren();
        //业务
        sleep();


    }

    private static void sleep() {
        try {
            Thread.sleep(Long.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void getChlidren() throws KeeperException, InterruptedException {
        List<String> children = zkClient.getChildren("/servers", true);
        List<String> list = new ArrayList<>();
        for (String child : children) {
            list.add(new String(zkClient.getData("/servers/" + child, false, null)));

        }
        System.out.println(list);
    }

    private static void getConnection() {
        try {
            zkClient = new ZooKeeper(connectionString, sessionTime, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    try {
                        getChlidren();
                    } catch (KeeperException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}

Zookeeper面试常见问题:

  • 请简述zookeeper选举机制:
  • Zookeeper监听原理:
  • Zookeeper的部署方式有那几种?集群中的角色有那些?集群最少需要几台?
    • 部署方式为单击模式集群模式
    • 角色:LeaderFollower
    • 集群最少三台(原因)
  • Zookeeper的常用命令:
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值