Zookeeper的基本使用、配置为注册中心

本文介绍了Zookeeper的基础使用,包括其类似文件系统的数据结构和监听通知机制。详细讲解了Zookeeper的安装过程,特别是配置参数如initLimit、syncLimit和tickTime。此外,还展示了如何在Spring Cloud中将Zookeeper用作注册中心,服务提供者和消费者的配置与实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Zookeeper

官方文档上这么解释zookeeper,它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

上面的解释有点抽象,简单来说zookeeper=文件系统+监听通知机制。

Zookeeper维护一个类似文件系统的数据结构:

在这里插入图片描述
每个子目录项如 NameService 都被称作为 znode(目录节点),和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。

在这里插入图片描述

  在装有 ZooKeeper 的机器的终端执行 zookeeper-server status 可以看当前节点的 
  ZooKeeper是什么角色(Leader or Follower)。

1.节点读写服务分工

   1.ZooKeeper 集群的所有机器通过一个 Leader 选举过程来选定一台被称为『Leader』
   的机器,Leader服务器为客户端提供读和写服务。
   2.Follower 和 Observer 都能提供读服务,不能提供写服务。两者唯一的区别在于,
   Observer机器不参与 Leader 选举过程,也不参与写操作的『过半写成功』策略,因
   此 Observer 可以在不影响写性能的情况下提升集群的读性能。

2 . Session

      Session 是指客户端会话,在讲解客户端会话之前,我们先来了解下客户端连接。在
  ZooKeeper 中,一个客户端连接是指客户端和 ZooKeeper 服务器之间的TCP长连接。

       ZooKeeper 对外的服务端口默认是2181,客户端启动时,首先会与服务器建立一个TCP
  连接,从第一次连接建立开始,客户端会话的生命周期也开始了,通过这个连接,客户端能够通
  过心跳检测和服务器保持有效的会话,也能够向 ZooKeeper 服务器发送请求并接受响应,同
  时还能通过该连接接收来自服务器的 Watch 事件通知。

      Session 的 SessionTimeout 值用来设置一个客户端会话的超时时间。当由于服务器
  压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在 
  SessionTimeout 规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话
  仍然有效。

3 . 数据节点

    zookeeper的结构其实就是一个树形结构,leader就相当于其中的根结点,其它节点就相当于
 follow节点,每个节点都保留自己的内容。

     zookeeper的节点分两类:持久节点和临时节点
     - 持久节点:
             所谓持久节点是指一旦这个 树形结构上被创建了,除非主动进行对树节点的移除操
        作,否则这个 节点将一直保存在 ZooKeeper 上。

     - 临时节点:
             临时节点的生命周期跟客户端会话绑定,一旦客户端会话失效,那么这个客户端创
        建的所有临时节点都会被移除。

4 . 状态信息

    每个 节点除了存储数据内容之外,还存储了 节点本身的一些状态信息。用 get 命令可以
同时获得某个 节点的内容和状态信息
    在 ZooKeeper 中,version 属性是用来实现乐观锁机制中的『写入校验』的(保证分布
式数据原子性操作)。

5.事物操作

    在ZooKeeper中,能改变ZooKeeper服务器状态的操作称为事务操作。一般包括数据节点
创建与删除、数据内容更新和客户端会话创建与失效等操作。对应每一个事务请求,ZooKeeper
都会为其分配一个全局唯一的事务ID,用 ZXID 表示,通常是一个64位的数字。每一个 ZXID
对应一次更新操作,从这些 ZXID 中可以间接地识别出 ZooKeeper 处理这些事务操作请求的
全局顺序。

6.Watcher(事件监听器)

    是 ZooKeeper 中一个很重要的特性。ZooKeeper允许用户在指定节点上注册一些 Watcher,
并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去。该
机制是 ZooKeeper 实现分布式协调服务的重要特性。

7.ZooKeeper应用的典型场景

    ZooKeeper 是一个高可用的分布式数据管理与协调框架。基于对ZAB算法的实现,该框架
能够很好地保证分布式环境中数据的一致性。也是基于这样的特性,使得 ZooKeeper 成为了
解决分布式一致性问题的利器。

监听通知机制

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。
在这里插入图片描述

1 . 数据发布与订阅(配置中心)

  数据发布与订阅,即所谓的配置中心,顾名思义就是发布者将数据发布到 ZooKeeper 节点上,
供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中式管理和动态更新。

    对于:数据量通常比较小。数据内容在运行时动态变化。集群中各机器共享,配置一致。
这样的全局配置信息就可以发布到 ZooKeeper上,让客户端(集群的机器)去订阅该消息。

发布/订阅系统一般有两种设计模式,分别是推(Push)和拉(Pull)模式。
      - 推模式
          服务端主动将数据更新发送给所有订阅的客户端
      - 拉模式
          客户端主动发起请求来获取最新数据,通常客户端都采用定时轮询拉取的方式

ZooKeeper 采用的是推拉相结合的方式:
    客户端想服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应
的客户端发送Watcher事件通知,客户端接收到这个消息通知后,需要主动到服务端获取最新的数据

2 . 命名服务

    命名服务也是分布式系统中比较常见的一类场景。在分布式系统中,通过使用命名服务,客户端
应用能够根据指定名字来获取资源或服务的地址,提供者等信息。被命名的实体通常可以是集群中的
机器,提供的服务,远程对象等等——这些我们都可以统称他们为名字。

其中较为常见的就是一些分布式服务框架(如RPC)中的服务地址列表。通过在ZooKeepr里
创建顺序节点,能够很容易创建一个全局唯一的路径,这个路径就可以作为一个名字。

ZooKeeper 的命名服务即生成全局唯一的ID。      

3 . 分布式协调服务/通知

    ZooKeeper 中特有 Watcher 注册与异步通知机制,能够很好的实现分布式环境下不同机器,
甚至不同系统之间的通知与协调,从而实现对数据变更的实时处理。使用方法通常是不同的客户端
如果 机器节点 发生了变化,那么所有订阅的客户端都能够接收到相应的Watcher通知,并做出相应
的处理。
ZooKeeper的分布式协调/通知,是一种通用的分布式系统机器间的通信方式。

4 . Master选举

    针对 Master 选举的需求,通常情况下,我们可以选择常见的关系型数据库中的主键特性来
实现:希望成为 Master 的机器都向数据库中插入一条相同主键ID的记录,数据库会帮我们进行
主键冲突检查,也就是说,只有一台机器能插入成功——那么,我们就认为向数据库中成功插入数据
的客户端机器成为Master。

    依靠关系型数据库的主键特性确实能够很好地保证在集群中选举出唯一的一个Master。

    但是,如果当前选举出的 Master 挂了,那么该如何处理?谁来告诉我 Master 挂了呢?
显然,关系型数据库无法通知我们这个事件。但是,ZooKeeper 可以做到!

    利用 ZooKeepr 的强一致性,能够很好地保证在分布式高并发情况下节点的创建一定能够
保证全局唯一性,即 ZooKeeper 将会保证客户端无法创建一个已经存在的 数据单元节点。
    也就是说,如果同时有多个客户端请求创建同一个临时节点,那么最终一定只有一个客户端
请求能够创建成功。利用这个特性,就能很容易地在分布式环境中进行 Master 选举了。

    成功创建该节点的客户端所在的机器就成为了 Master。同时,其他没有成功创建该节点的
客户端,都会在该节点上注册一个子节点变更的 Watcher,用于监控当前 Master 机器是否存
活,一旦发现当前的Master挂了,那么其他客户端将会重新进行 Master 选举。

    这样就实现了 Master 的动态选举。

安装

使用centos7进行安装,需要有jdk环境
下载地址:http://mirror.bit.edu.cn/apache/zookeeper/

tar -zxvf zookeeper-3.4.14.tar.gz

创建dataDir文件夹

mkdir data

配置文件位于conf文件夹中,文件名必须为zoo.cfg

cp zoo_sample.cfg zoo.cfg

tickTime=2000
initLimit=10
syncLimit=5
#zookeeper下新建了一个data文件夹用来当作dataDir
dataDir=/my_dev/zookeeper/data
#启动端口号
clientPort=2181
sever.1=ip:2888:3888
  • initLimit
    ZooKeeper集群模式下包含多个zk进程,其中一个进程为leader,余下的进程为follower。当follower最初与leader建立连接时,它们之间会传输相当多的数据,尤其是follower的数据落后leader很多。initLimit配置follower与leader之间建立连接后进行同步的最长时间。
  • syncLimit
    配置follower和leader之间发送消息,请求和应答的最大时间长度。
  • tickTime
    tickTime则是上述两个超时配置的基本单位,例如对于initLimit,其配置值为5,说明其超时时间为 2000ms* 5 = 10秒。
  • server.id=host:port1:port2
    其中id为一个数字,表示zk进程的id,这个id也是dataDir目录下myid文件的内容。
    host是该zk进程所在的IP地址,port1表示follower和leader交换消息所使用的端口,port2表示选举leader所使用的端口。
    例如:server.1=IP:2888:3888 2888端口号是zookeeper服务之间通信的端口。3888是zookeeper与其他应用程序通信的端口。 启动,脚本位于bin文件夹中
  • dataDir
    其配置的含义跟单机模式下的含义类似,不同的是集群模式下还有一个myid文件。myid文件的内容只有一行,且内容只能为1 - 255之间的数字,这个数字亦即上面介绍server.id中的id,表示zk进程的id。
    现在,在dataDir=/home/zookeeper-3.4.12/data 下创建myid文件(编辑myid文件,并在对应的IP的机器上输入对应的编号。例如:在安装zookeeper机器上,myid 文件内容就是1。如果只在单点上进行安装配置,那么只有一个server.1)
    启动
#启动zookeeper
./zkServer.sh start
#查看启动状态
./zkServer.sh status
#客户端登陆
./zkCli.sh -server 127.0.0.1:2181

cli常用命令

  • s 创建有序节点

如果在创建znode时,我们使用排序标志的话,ZooKeeper会在我们指定的 znode 名字后面增加一个数字。我们继续加入相同名字的znode时,这个数字会不断增加。这个序号的计数器是由这些排序znode的父节点来维护的。

  • -e 创建临时节点

znode有两种类型:ephemeral 和 persistent。在创建znode时,我们指定znode的类型,并且在之后不会再被修改。当创建znode的客户端的session结束后,ephemeral类型的znode将被删除。persistent类型的znode在创建以后,就与客户端没什么联系了,除非主动去删除它,否则他会一直存在。Ephemeral znode没有任何子节点。

[zk: 127.0.0.1:2181(CONNECTED) 7] create /nodeTest hello
Created /nodeTest
[zk: 127.0.0.1:2181(CONNECTED) 8] create /nodeTest/subNode aaa 
Created /nodeTest/subNode
[zk: 127.0.0.1:2181(CONNECTED) 9] get /nodeTest
hello
cZxid = 0x2
ctime = Sat Sep 05 16:56:23 CST 2020
mZxid = 0x2
mtime = Sat Sep 05 16:56:23 CST 2020
pZxid = 0x3
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 1
[zk: 127.0.0.1:2181(CONNECTED) 13] get /nodeTest/subNode 
aaa
cZxid = 0x3
ctime = Sat Sep 05 16:56:42 CST 2020
mZxid = 0x3
mtime = Sat Sep 05 16:56:42 CST 2020
pZxid = 0x3
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
[zk: 127.0.0.1:2181(CONNECTED) 15] ls /
[zookeeper, nodeTest]
#使用 ls 命令来查看某个目录包含的所有文件,例如:
[zk: 127.0.0.1:2181(CONNECTED) 1] ls /
#使用 ls2 命令来查看某个目录包含的所有文件,与ls不同的是它查看到time、version等信息
[zk: 127.0.0.1:2181(CONNECTED) 1] ls2 /
#create命令 创建znode,并设置初始内容,例如
[zk: 127.0.0.1:2181(CONNECTED) 1] create /test "hello" 
#get命令,获取znode的数据,如下:
[zk: 127.0.0.1:2181(CONNECTED) 1] get /test
#set命令,修改znode内容,例如:
[zk: 127.0.0.1:2181(CONNECTED) 1] set /test "ricky"
#delete命令,删除znode
[zk: 127.0.0.1:2181(CONNECTED) 1] delete /test
#quit 退出客户端
#help  帮助命令

Spring Cloud使用Zookeeper作为注册中心

在这里插入图片描述

服务提供者

启动类添加@EnableDiscoveryClient注解
依赖

       <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
       </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
        </dependency>

application.yml

server:
  port: 8003
#服务别名----注册zookeeper到注册中心名称
spring:
  application:
    name: cloud-provider-payment
  cloud:
    zookeeper:
      connect-string: 192.168.182.20:2181

启动项目后查看zookeeper多个一个Services节点。里面保存了服务信息

[zk: localhost:2181(CONNECTED) 14] ls /
[services, zookeeper]
[zk: localhost:2181(CONNECTED) 22] ls /services
[cloud-provider-payment]
[zk: localhost:2181(CONNECTED) 23] ls /services/cloud-provider-payment
[874bc712-ddd1-4d12-8166-e7a923334f9e]
[zk: localhost:2181(CONNECTED) 25] get  /services/cloud-provider-payment/874bc712-ddd1-4d12-8166-e7a923334f9e
{"name":"cloud-provider-payment","id":"874bc712-ddd1-4d12-8166-e7a923334f9e","address":"DESKTOP-P0QVNOL","port":8003,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","name":"cloud-provider-payment","metadata":{"instance_status":"UP"}},"registrationTimeUTC":1599298250684,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}
cZxid = 0xc
ctime = Sat Sep 05 17:30:51 CST 2020
mZxid = 0xc
mtime = Sat Sep 05 17:30:51 CST 2020
pZxid = 0xc
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x10000168b2d0003
dataLength = 558
numChildren = 0

消费者

依赖和application.yml与服务提供者的类似,启动类也要添加@EnableDiscoveryClient
Controller类

@RestController
@Slf4j
public class ConsumerController {

    private final String INVOKE_URL="http://cloud-provider-payment";
    
    @Autowired
    private RestTemplate restTemplater;

    @GetMapping("/consumer")
    public String consumerTest(){
        return restTemplater.getForObject(INVOKE_URL+"/payment/zk",String.class);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值