Zookeeper入门到精通

一、概述

  ZooKeeper 是 Apache 软件基金会的一个软件项目,它为大型分布式计算提供开源的分布式配置服务、同步服务和命名注册;一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。

1.1 工作机制

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

1.2 特点

  • Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群
  • 集群中只要有半数以上节点存活,Zookeeper集群就能正常服务(Zookeeper适合安装奇数台服务器)
  • 全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的
  • 更新请求顺序执行,来自同一个Client的更新请求按其发送顺序依次执行
  • 数据更新原子性,一次数据更新要么成功,要么失败
  • 实时性,在一定时间范围内,Client能读到最新数据

1.3 数据结构

  ZooKeeper 数据模型的结构与Unix文件系统很类似,整体上可以看作是一棵树,每个节点称做一个ZNode。每一个ZNode默认能够存储1MB的数据,每个ZNode都可以通过其路径唯一标识。

二、安装

2.1 本地安装(单机)

详细安装配置步骤参照 Zookeeper安装配置

2.2 docker安装(集群)

  • 编写 zookeeper-cluster.yml 文件,具体内容如下:
version: '3.0'

services:
  zookeeper1:
    image: zookeeper:3.8.0
    restart: always
    hostname: zookeeper1
    ports:
      - 2181:2181
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181 server.2=zookeeper2:2888:3888;2181 server.3=zookeeper3:2888:3888;2181

  zookeeper2:
    image: zookeeper:3.8.0
    restart: always
    hostname: zookeeper2
    ports:
      - 2182:2181
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zookeeper1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zookeeper3:2888:3888;2181

  zookeeper3:
    image: zookeeper:3.8.0
    restart: always
    hostname: zookeeper3
    ports:
      - 2183:2181
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zookeeper1:2888:3888;2181 server.2=zookeeper2:2888:3888;2181 server.3=0.0.0.0:2888:3888;2181
  • 启动集群容器:COMPOSE_PROJECT_NAME=cluster docker-compose -f zookeeper-cluster.yml up -d
  • 查看运行中的 Zookeeper 集群:docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED         STATUS                 PORTS                                                                     NAMES
15d7acedb767   zookeeper:3.8.0       "/docker-entrypoint.…"   6 seconds ago   Up 4 seconds           2888/tcp, 3888/tcp, 8080/tcp, 0.0.0.0:2182->2181/tcp, :::2182->2181/tcp   cluster-zookeeper2-1
3e5d406c05b6   zookeeper:3.8.0        "/docker-entrypoint.…"   6 seconds ago   Up 4 seconds           2888/tcp, 3888/tcp, 8080/tcp, 0.0.0.0:2183->2181/tcp, :::2183->2181/tcp   cluster-zookeeper3-1
f47df87b1ac9   zookeeper:3.8.0       "/docker-entrypoint.…"   6 seconds ago   Up 4 seconds           2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, :::2181->2181/tcp, 8080/tcp   cluster-zookeeper1-1

非docker方式集群搭建可参考 Zookeeper linux 服务端集群搭建步骤

三、选举机制

3.1 重要参数及选举状态

三大参数:

  • 服务器 ID(myid/sid):编号越大在选举算法中权重越大
  • 事务 ID(zxid):值越大说明数据越新,权重越大
  • 逻辑时钟(epoch-logicalclock):同一轮投票过程中的逻辑时钟值是相同的,每投完一次值会增加

四大选举状态:

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

3.2 第一次启动

  每个节点启动的时候都 LOOKING 观望状态,接下来就开始进行选举主流程。这里选取五台机器组成的集群为例。第一台服务器 server1启动时,无法进行 leader 选举,当第二台服务器 server2 启动时,两台机器可以相互通信,进入 leader 选举过程。具体过程如下:
(1)服务器1启动,发起一次选举。服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成,服务器1状态保持为LOOKING;
(2)服务器2启动,再发起一次选举。服务器1和2分别投自己一票并交换选票信息:此时服务器1发现服务器2的myid比自己目前投票推举的(服务器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一样当小弟。

3.3 运行过程中

当集群中 leader 服务器出现宕机或者不可用情况时,整个集群无法对外提供服务,进入新一轮的 leader 选举。具体过程如下:
(1)变更状态。leader 挂后,其他非Oberver服务器将自身服务器状态变更为 LOOKING。
(2)每个 server 发出一个投票。在运行期间,每个服务器上 zxid 可能不同。
(3)处理投票。规则同启动过程。
(4)统计投票。与启动过程相同。
(5)改变服务器状态。与启动过程相同。

选举Leader规则: EPOCH大的直接胜出;EPOCH相同,事务id(zxid)大的胜出;事务id相同,服务器id(sid)大的胜出

四、节点(znode)结构

  zookeeper 中的所有存储的数据是由 znode 组成的,节点也称为 znode,并以 key/value 形式存储数据。整体结构类似于 linux 文件系统的模式以树形结构存储。其中根路径以 /开头。节点类型可分为两大类:

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

  • 持久化节点:客户端与Zookeeper断开连接后,该节点依旧存在
  • 持久化顺序节点:客户端与Zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号

(2)短暂(Ephemeral):客户端和服务器端断开连接后,创建的节点自己删除

  • 临时节点:客户端与Zookeeper断开连接后,该节点被删除
  • 临时顺序节点:客户端与 Zookeeper 断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

五、客户端命令行操作

命令基本语法功能描述
help显示所有操作命令
ls path查看当前 znode 的子节点 [可监听](-w 监听子节点变化;-s 附加次级信息)
create创建普通节点(-s 有序;-e 临时)
get path获得节点的值 [可监听](-w 监听子节点变化;-s 附加次级信息)
set设置(修改)节点的具体值
stat查看节点状态
delete删除节点
deleteall递归删除节点

Znode 的状态属性:

[zk: localhost:2181(CONNECTED) 1] ls /demo -s
[]cZxid = 0x100000004   -- 创建节点时的事务ID
ctime = Sat Oct 15 16:26:56 UTC 2022  -- 创建节点时的时间
mZxid = 0x100000004  -- 最后修改节点时的事务ID
mtime = Sat Oct 15 16:26:56 UTC 2022  -- 最后修改节点时的时间
pZxid = 0x100000004  -- 表示该节点的子节点列表最后一次修改的事务ID,添加子节点或删除子节点就会影响子节点列表,但是修改子节点的数据内容则不影响该ID
cversion = 0   -- 子节点版本号,子节点每次修改版本号加1
dataVersion = 0   -- 数据版本号,数据每次修改该版本号加1
aclVersion = 0   -- 权限版本号,权限每次修改该版本号加1
ephemeralOwner = 0x0   -- 创建该临时节点的会话的sessionID。(如果该节点是持久节点,那么这个属性值为0)
dataLength = 0   -- 该节点的数据长度
numChildren = 0   -- 该节点拥有子节点的数量

六、客户端API操作

Zookeeper 客户端连接常见两种方式:原生 API 和 Curator 两种方式

6.1 原生 API

建立maven项目及引入相关依赖:

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.8.0</version>
</dependency>

建立连接:

public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
	final CountDownLatch countDownLatch = new CountDownLatch(1);
	ZooKeeper zooKeeper =
	        new ZooKeeper("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183",
	                4000, event -> {
	            if (Watcher.Event.KeeperState.SyncConnected == event.getState()) {
	                // 如果收到了服务端的响应事件,连接成功
	                countDownLatch.countDown();
	            }
	        });
	countDownLatch.await();
	// CONNECTED
	System.out.println(zooKeeper.getState());

    // 创建持久接待您
    zooKeeper.create("/demo","zookeeper-znodes-values".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
}

6.2 Curator

   Curator 是 Netflix 公司开源的一套 zookeeper 客户端框架,解决了很多 Zookeeper 客户端非常底层的细节开发工作,包括连接重连、反复注册 Watcher 和 NodeExistsException 异常等。
建立maven项目及引入相关依赖:

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.2.0</version>
</dependency>

建立连接:

public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
	CuratorFramework curatorFramework = CuratorFrameworkFactory.
                builder().connectString("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183")
                .sessionTimeoutMs(4000)
                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
                .namespace("").build();
    curatorFramework.start();
    Stat stat = new Stat();
    //查询节点数据
    byte[] bytes = curatorFramework.getData().storingStatIn(stat).forPath("/demo");
    System.out.println(new String(bytes));
    curatorFramework.close();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值