栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

[04][02][01] ZooKeeper 基础

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

[04][02][01] ZooKeeper 基础

文章目录
  • 1. ZooKeeper 基本概率
    • 1.1 服务架构
    • 1.2 分层命名空间
    • 1.3 简单的 API
  • 2. 结点状态信息 Stat
  • 3. watcher 机制
    • 3.1 一次性监听
    • 3.2 长久监听
  • 4. Session 会话机制
  • 5. ZooKeeper 权限控制 (ACL)
    • 5.1 Scheme 权限模式
    • 5.2 Id 授权对象
    • 5.3 Permission 权限类型
  • 6. 自己实现配置中心
    • 6.1 读取本地自定义配置
    • 6.2 监听 ZooKeeper 动态加载配置
  • 7. Curator 框架
    • 7.1 Curator 实现分布式锁
    • 7.2 Curator 实现 Leader 选举

1. ZooKeeper 基本概率

Apache ZooKeeper 提供高可靠的分布式协调服务, 用于维护配置信息, 命名, 提供分布式同步和提供组服务

官网地址: https://ZooKeeper.apache.org

1.1 服务架构

1.2 分层命名空间

ZooKeeper 提供的命名空间很像标准文件系统, 名称是由 / 和结点名称 组成路径信息

1.3 简单的 API

ZooKeeper 提供非常简单的编程接口

  • create 在树中的某个位置创建一个节点
  • delete 删除一个节点
  • exists 测试节点是否存在于某个位置
  • get data 从节点读取数据
  • set data 将数据写入节点
  • get children 检索节点的子节点列表
  • sync 等待数据传播
2. 结点状态信息 Stat

通过 get 命令可以获取结点状态的详细信息

ZooKeeper 为数据节点增加三个版本信息, 对数据节点任何更新操作都会引起版本号的变化, 就是用来实现乐观锁机制的“写入校验”

3. watcher 机制

ZooKeeper 提供了分布式数据的发布/订阅功能, ZooKeeper 允许客户端向服务端注册一个 watcher 监听, 当服务端的一些指定事件触发了 watcher, 那么服务端就会向客户端发送一个事件通知

对指定节点设置监听的命令

3.1 一次性监听
  • 监听指定 path 节点的修改和删除事件, 一次性触发
get [-s] [-w] path

stat [-w] path

# 例如
get -w /node
# 在其他窗口执行下面命令,会触发相关事件
set /node 123
delete /node
  • 监控指定 path 的子节点的添加和删除事件
`ls [-s] [-w] [-R] path

# 例如
ls -w /node
# 在其他窗口执行下面命令,会触发相关事件
create /node/node1
delete /node/node1
3.2 长久监听
addWatch [-m mode] path 

mode 支持两种模式

  • RSISTENT, 持久化订阅, 针对当前节点的修改和删除事件, 以及当前节点的子节点的删除和新增事件

  • RSISTENT_RECURSIVE(默认实现), 持久化递归订阅, 在 PERSISTENT 的基础上, 增加了子节点修改的事件触发, 以及子节点的子节点的数据变化都会触发相关事件 (满足递归订阅特性)

4. Session 会话机制

  • 客户端向 ZooKeeper Server 发起连接请求, 此时状态为 CONNECTING
  • 当连接建立好之后, Session 状态转化为 CONNECTED, 此时可以进行数据的 IO 操作
  • 如果 Client 和 Server 的连接出现丢失, 则 Client 又会变成 CONNECTING 状态
  • 如果会话过期或者主动关闭连接时, 此时连接状态为 CLOSE
  • 如果是身份验证失败, 直接结束
5. ZooKeeper 权限控制 (ACL)

提供了一套 ACL 权限控制机制来保证数据的安全

使用 scheme : id : permission 来标识

  • scheme 权限模式, 标识授权策略
  • id 授权对象
  • permission 授予的权限

ZooKeeper 的权限控制是基于每个 znode 节点的, 需要对每个节点设置权限, 每个 znode 支持设置多种
权限控制方案和多个权限, 子节点不会继承父节点的权限, 客户端无权访问某节点, 但可能可以访问它
的子节点

5.1 Scheme 权限模式
  • world: 默认方式, 相当于全部都能访问
  • auth: 代表已经认证通过的用户 (cli 中可以通过 addauth digest user:pwd 来添加当前上下文中的授权用户)
  • digest: 即用户名: 密码这种方式认证, 这也是业务系统中最常用的. 用 username:password 字符串来产生一个 MD5 串, 然后该串被用来作为 ACL ID. 认证是通过明文发送 username:password 来进行的, 当用在 ACL 时, 表达式为 username:base64, base64 是 password 的 SHA1 摘要的编码
  • ip: 通过 ip 地址来做权限控制, 比如 ip:192.168.1.1 表示权限控制都是针对这个 ip 地址的. 也可以针对网段 ip:192.168.1.1/24, 此时 addr 中的有效位与客户端 addr 中的有效位进行比对
5.2 Id 授权对象

指权限赋予的用户或一个指定的实体, 不同的权限模式下, 授权对象不同

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nC3WWQpv-1650455459196)(en-resource://database/2193:1)]

Id ipId1 = new Id("ip", "192.168.190.1");
Id ANYONE_ID_UNSAFE = new Id("world", "anyone");
5.3 Permission 权限类型

指通过权限检查后可以被允许的操作

  • Create 允许对子节点 Create 操作
  • Read 允许对本节点 Get Children 和 Get Data 操作
  • Write 允许对本节点 Set Data 操作
  • Delete 允许对子节点 Delete 操作
  • Admin 允许对本节点 setAcl 操作

权限模式 (Schema) 和授权对象 (Id) 主要用来确认权限验证过程中使用的验证策略: 比如 ip 地址, digest:username:password, 匹配到验证策略并验证成功后, 再根据权限操作类型来决定当前客户端的访问权限

6. 自己实现配置中心 6.1 读取本地自定义配置
  • 通过 CustomEnvironmentPostProcessor 类实现 Spring 的 EnvironmentPostProcessor 接口
  • 在 META-INF/spring.factories 中配置接口和实现类的全限定名信息
  • 加载 custom.properties 中的配置信息
  • 可以在 Environment 中查询到用户自定义的配置信息

EnvironmentPostProcessor 的实现类

public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {
    private static final String PROPERTIES_RESOURCE_LOCATION = "custom.properties";

    private final Properties properties = new Properties();

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        Resource resource = new ClassPathResource(PROPERTIES_RESOURCE_LOCATION);
        environment.getPropertySources().addLast(loadProperties(resource));
    }

    private PropertySource loadProperties(Resource resource) {
        try {
            properties.load(resource.getInputStream());
            return new PropertiesPropertySource(resource.getFilename(), properties);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

META-INF 下的 spring.factories 文件

org.springframework.boot.env.EnvironmentPostProcessor=com.example.springbootZooKeeper.CustomEnvironmentPostProcessor

custom.properties 文件

test.info=Hello SPI

使用自定义配置文件的业务代码

@RestController
public class ConfigController {
    @Autowired
    Environment environment;

    @GetMapping("/env")
    public String env(){
        return environment.getProperty("test.info");
    }
}
6.2 监听 ZooKeeper 动态加载配置 7. Curator 框架

Curator 是 ZooKeeper 的客户端, 对其 api 的封装以及扩展

主要特性

  • Elections (选举)
  • Locks (分布式锁)
  • Shared Reentrant Lock: 全局同步的完全分布式锁, 这意味着在任何时间快照中, 没有两个客户端认为他们持有相同的锁
  • Shared Lock: 类似于 Shared Reentrant Lock 不可重入
  • Shared Reentrant Read Write Lock: 跨 JVM 工作的可重入读/写互斥锁
  • Shared Semaphore: 跨 JVM 实现 Semaphore
  • Multi Shared Lock: 将多个锁作为单个实体进行管理的容器. 当调用 acquire() 时, 将获取所有锁. 如果失败, 则释放所有获取的路径. 同样, 当调用 release() 时, 所有锁都被释放 (忽略失败)
  • Barriers (屏障)
  • Barrier: 分布式系统使用 Barrier 来阻塞一组节点的处理, 直到满足一个条件, 此时所有节点都可以继续进行
  • Double Barrier: 双屏障使客户端能够同步计算的开始和结束. 当足够多的进程加入 barrier 时, 进程开始计算, 并在计算完成后离开 barrier
  • Counters (计数器)
  • Shared Counter: 管理共享整数
  • Distributed Atomic Long: 分布式原子自增的计数器
  • Caches (缓存)
  • Nodes/Watches (结点/观察者)
  • Queues (队列)
7.1 Curator 实现分布式锁

利用 ZooKeeper 同级节点的唯一性, 多个进程往 ZooKeeper 的指定节点下创建一个相同名称的节点, 只有一个能成功, 其他是创建失败
创建失败的节点全部通过 ZooKeeper 的 watcher 机制来监听这个节点的变化, 一旦监听到子节点的删除事件, 则再次触发所有进程去写锁

如果遇到大批量访问场景会对性能要求高, 可以通过有序节点来实现分布式锁, 客户端都往指定的节点下注册一个临时有序节点, 越早创建的节点, 节点的顺序编号就越小, 将子节点中最小的节点设置为获得锁

如果自己的节点不是最小的, 每个节点只需要监听比自己小的节点, 当比自己小的节点删除以后, 客户端会收到 watcher 事件, 此时再次判断自己的节点是不是所有子节点中最小的, 如果是则获得锁

代码样例

// 创建锁对象
InterProcessMutex lock = new InterProcessMutex(CuratorFramework, NODE_PATH);
// 尝试获取锁
lock.acquire(100, TimeUnit.MILLISECONDS);
System.out.printf("获取锁成功");
// 锁释放
lock.release();
System.out.printf("释放锁成功");

源码解读

public InterProcessMutex(CuratorFramework client, String path){
	// ZooKeeper 利用 path 创建临时顺序节点,实现公平锁的核心
	this(client, path, new StandardLockInternalsDriver());
}

// 无限等待获取锁
public void acquire()throws Exception {
	if ( !internalLock(-1, null)){
		throw new IOException("Lost connection while trying to acquire lock: " + basePath);
	}
}

// 限时等待获取锁
public boolean acquire(long time, TimeUnit unit)throws Exception {
	return internalLock(time, unit);
}

// 锁释放
 public void release() throws Exception {
        Thread currentThread = Thread.currentThread();
        InterProcessMutex.LockData lockData = (InterProcessMutex.LockData)this.threadData.get(currentThread);
       .....
       // 锁重入次数
        int newLockCount = lockData.lockCount.decrementAndGet();
        .....
        try {
            this.internals.releaseLock(lockData.lockPath);
        } finally {
            this.threadData.remove(currentThread);
        }
        .....
}
7.2 Curator 实现 Leader 选举

Elections 有两种实现

  • Leader Latch: 核心思想是初始化多个 LeaderLatch, 然后在等待几秒钟后, Curator 会自动从中选举出 Leader, leader 会一直占用领导权
  • Leader Election: 让所有的实例轮流当 Leader, Leader 的实例在释放领导权之后, 该实例还可以再次竞争 Leader, 选举出来的 Leader 实例不会一直占有领导权
LeaderLatch leaderLatch = new LeaderLatch(CuratorFramework, NODE_PATH);
leaderLatch.addListener(xxxxx);
leaderLatch.addListener(xxxxx);
leaderLatch.addListener(xxxxx);
leaderLatch.addListener(xxxxx);
leaderLatch.start();
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/820231.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号