Spring Boot 2精髓 - (16) ZooKeeper

spring boot

SpringBoot水平扩展后,我们还面临一些挑战:

  • 一个时刻,只能有一个应用来处理某个业务,而不能发生同时处理的情况。
    这就需要提供一个分布式锁,只有获得锁的SpringBoot应用才能执行操作。
    执行完毕后,释放锁。
    比如定时调度某个任务执行,同一个时刻只能有一个SpringBoot应用能执行
  • 应用系统之间通过 REST 接口来相互调用,如何让 REST 客户端知道服务在哪里?
    SpringBoot应用可以水平扩展,不可能通过 application.properties来配置服务器地址
  • 需要在SpringBoot应用中选择一个领导节点,这个领导节点负责协调所有 SpringBoot 应用的工作

ZooKeeper

ZooKeeper 来源于Apache Hadoop子项目,是一个高性能分布式的、开源应用协调服务。
分布式应用可以基于它实现协调服务,比如同步集群领导选取,以及分布式系统的配置管理、命名服务。
使用文件系统目录树作为数据模型

ZooKeeper(下面简称 zk)有以下特点:

  • 简单的API和数据结构完成协调服务,zk提供了易于理解的数据结构来完成协调服务,其JavaAPI非常简单。
    Curator进一步封装了这些API,直接提供了分布式协调服务而不需要关心细节
  • 分布式,不会出现单点故障,一般来说,至少部署3台zk以避免单点故障。
    客户端(指Spring Boot应用)如果连接的zk宕机,客户端将自动连接到另外一台。
  • 保证操作的时序性,zk对每次更新都有时间戳记录,从而保证操作的时序性,保证可以完成更高层次的协调服务,如分布式锁。
  • 性能测试结果,zk 本身的性能非常好,既可以处理分布式系统的管理协调任务,如选举领导,也能胜任高井发量的业务协调处理,如业务处理的分布式锁。

ZooKeeper 的数据结构

zk提供的命名空间(name space)类似文件系统,每一个节点都是通过路径来表示的,不同的是,节点可以包含一定的数据(2MB 字节),这些节点可以用来存放业务信息,如配置信息等

节点还包含了更新的版本、时间戳。
有一种特殊的节点是临时节点,创建节点的会话存在,节点就存在,一旦会话结束,如客户端创建的连接断掉,或者客户端主动关闭此会话,则节点会被删除。
还可以指定节点为顺序节点,创建节点的时候,自动为节点增加一个序列号,井且序列号递增。

节点可以被监控,一旦节点变化,如删除节点,或者节点数据变化,客户端就会收到此事件,此监控失效。
客户端可以调用API继续监控这个节点

安装 ZooKeeper

ZooKeeper 官网 下载

zk 只需要解压即可使用

conf/zoo.cfg

  • tickTime 是心跳时间,默认是 2 秒
  • dataDir是 ZooKeeper保存的内存快照,以及事务日志的目录
  • clientPort 是客户端应用连接的端口

ZooKeeper 的基本命令

zkCli:

  • help, 进入命令行模式
  • ls, 查看目录
  • create, 创建节点
  • create -e,创建临时节点,一旦用户会话结束,则节点自动删除
  • get,获取节点数据
    节点内部数据:
    • cZxid,节点创建时的 zxid
    • mZxid,节点最新一次更新发生时的 zxid
    • ctime,节点创建时的时间戳
    • mtime,节点最新一次更新发生时的时间戳
    • dataVersion,节点数据的更新次数
    • cversion,其子节点的更新次数
    • aclVersion,节点ACL(授权信息)的更新次数
    • ephemeralOwner,如果该节点为临时节点,ephemeralOwner值表示与该节点绑定的会话ID,如果该节点不是临时节点, ephemeralOwner值为 0;
    • dataLength,节点数据的字节数
    • numChildren,子节点个数
  • delete,删除节点
  • set path data,设置节点数据
  • watch操作,ls命令和get命令都可以增加一个watch操作,节点变化的时候会通知客户端。
    通知完毕后,还需要再次调用 ls 或者 get才能监昕此节点变化

领导选取

分布式锁

服务注册

集成 ZooKeeper

Curator 是Apache提供的一个访问zk的工具包,封装了这些低级别操作,同时也提供一些高级服务,比如分布式锁、领导选取等

它具有如下特性:

  • 自动重连,无须开发人员关心
  • 提供简单的API来操作 zk 节点,还有zk事件,API是链式操作风格
  • Curator实现了ZooKeeper提供的所有应用场景(除了两阶段提交),有以下实现:
    • 领导节点选取
    • 分布式锁
    • 分布式读写锁
    • 共享信号量
    • 栅栏和双重 DoubleBarrier
    • 分布式计数器,支持integerlong
    • 分布式队列和分布式优先级队列
    • 服务注册和发现

集成 Curator

依赖:

1
2
3
4
5
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-x-discovery</artifactId>
<version>4.0.1</version>
</dependency>

Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class ZookeeperConf {
@Value("${zk.url}")
private String zkUrl;

@Bean
public CuratorFramework getCuratorFramework() throws Exception {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client = CuratorFrameworkFactory.newClient(zkUrl, retryPolicy);

client.start();
return client;
}
}

RetryPolicy 用于重连策略

Curator API

  • create,创建节点,也可通过withMode为节点设置类型,如临时节点、序列节点,以forPath结尾。
    如果节点己经存在,抛出 NodeExistsExceptiono
  • delete,删除节点,以forPath结尾,如果节点不存在,将抛出 NoNodeException,
    如果节点是非空节点,则抛出 NotEmptyExceptiono
  • checkExists(),检查节点是否存在,如果不存在,返回 null,如果存在,返回 Stat对象。
    可以加上 watch 方法来监听节点变化,该方法以 forPath 结尾
  • getData,获取节点数据,以 forPath 结尾,返回 byte[]
  • setData,设置节点数据,以 forPath结尾
  • getChildren(),得到节点的子节点,以forPath结尾,返回一个子节点路径列表

实现分布式锁

Curator提供了InterProcessMutex来实现分布式锁
InterProcessMutexacquire方法获取锁,
以及用release释放锁,同其他锁一样,release方法需要放在finally代码块中,确保锁能正确释放

服务注册

curator-x-discovery

通过 ServiceDiscovery 注册服务

获取服务

领导选取

LeaderSelector 即可实现领导的选取

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2021 朝着牛逼的道路一路狂奔 All Rights Reserved.

访客数 : | 访问量 :