ZooKeeper 介绍
ZooKeeper 一个中心化的服务, 用于维护配置信息, 命名服务(naming), 提供分布式同步和集群服务(group services)。
它是一个开源的分布式应用程序协调服务, 作为 Google Chubby的一个开源实现, 是Hadoop和Hbase的重要组件。 ZooKeeper 的目标是封装好复杂易出错的关键服务, 暴露简单易用、高效、稳定的接口给用户使用, 提供基于java和C的接口。
Zookeeper 的核心实现是一个分布式的数据存储系统,其内部采用 ZAB 协议(Zookeeper Atomic Broadcast)进行主从复制,确保了数据的一致性和可靠性。在 Zookeeper 中,数据存储采用了一种称为“Znode”的数据模型,类似于 Unix 文件系统。
Znode 是 Zookeeper 中最基本的数据单元,是一个有层级的树形结构,每个节点都有一个路径,其中根节点为“/”,子节点路径会在父节点路径的基础上加上相对路径,最终形成一棵完整的树形结构。
Zookeeper的设计目标
简单
ZooKeeper 允许分布式的进程之间通过一个共享的层级命名空间(hierarchinal namespace, 和文件系统类似)进行协调。
ZK 实现了高性能、高可用和严格顺序访问, 是的它可以用于大规模分布式系统, 无单点故障问题, 和复杂的同步原语。
ZK 提供了简单的编程接口。
复制的(replicated)
ZooKeeper和其它的分布式进程一样, 也是一个集群的主机作为一个整体。
有序(ordered)
ZooKeeper用一个数字表示每一次的更新, 以反映所有 ZooKeeper 事务的顺序。后续可以利用这个顺序来实现诸如同步原语之类的高级抽象。
快速(fast)
ZooKeeper在读多写少的负载中性能尤其高, 读写比例大概处于 10:1 时表现最好。
Zookeeper的数据模型
Zookeeper使用一种树状数据模型来表示数据结构。每个节点在这个树状结构中都有一个唯一的路径,这个路径由节点的绝对路径组成。绝对路径是一个以斜杠(/)开头的字符串,表示从根节点到当前节点的路径。
Zookeeper的数据模型包括以下几个组成部分:
节点:节点是Zookeeper中的基本数据结构,它可以存储数据和元数据。
路径:路径是节点的唯一标识,用于表示节点在树状结构中的位置。
父节点:每个节点都有一个父节点,表示它在树状结构中的父节点。
子节点:每个节点都可以有多个子节点,表示它在树状结构中的子节点。
Zookeeper的数据操作
Zookeeper提供了一系列的数据操作接口,用于对数据进行CRUD操作。这些操作接口包括:
create:创建一个新节点。
get:获取一个节点的数据。
set:设置一个节点的数据。
delete:删除一个节点。
exists:检查一个节点是否存在。
sync:同步一个节点的数据。
Zookeeper实现分布式锁
分布式锁主要用于在分布式环境中保护跨进程、跨主机、跨网络的共享资源实现互斥访问,以达到保证数据的一致性。Zookeeper实现分布式锁是通过持久节点和临时顺序节点来完成的,实现思路如下:
获取锁:
1. 首先我们要有一个持久节点/locks,客户端获取锁就是在locks下创建临时顺序节点。
2. 假设客户端 1 创建了/locks/lock1节点,创建成功之后,会判断 lock1是否是 /locks 下最小的子节点。
3. 如果 lock1是最小的子节点,则获取锁成功。否则,获取锁失败。
4. 如果获取锁失败,则说明有其他的客户端已经成功获取锁。客户端 1 并不会不停地循环去尝试加锁,而是在前一个节点比如/locks/lock0上注册一个事件监听器。这个监听器的作用是当前一个节点释放锁之后通知客户端 1(避免无效自旋),这样客户端 1 就加锁成功了。
释放锁:
1. 成功获取锁的客户端在执行完业务流程之后,会将对应的子节点删除。
2. 成功获取锁的客户端在出现故障之后,对应的子节点由于是临时顺序节点,也会被自动删除,避免了锁无法被释放。
3. 我们前面说的事件监听器其实监听的就是这个子节点删除事件,子节点删除就意味着锁被释放。
Curator
实际项目中,推荐使用 Curator 来实现 ZooKeeper 分布式锁。Curator 是 Netflix 公司开源的一套 ZooKeeper Java 客户端框架,相比于 ZooKeeper 自带的客户端 zookeeper 来说,Curator的封装更加完善,各种API都可以比较方便地使用。Curator主要实现了下面四种锁:
InterProcessMutex:分布式可重入排它锁
InterProcessSemaphoreMutex:分布式不可重入排它锁
InterProcessReadWriteLock:分布式读写锁
InterProcessMultiLock:将多个锁作为单个实体管理的容器,获取锁的时候获取所有锁,释放锁也会释放所有锁资源(忽略释放失败的锁)。
以下是使用Curator的部分代码示例
在项目的pom.xml中引入Curator依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>5.6.0</version>
</dependency>
业务代码测试:
public String createOrderCurator(Integer productId, Integer count) throws Exception {
InterProcessMutex lock = new InterProcessMutex(curatorFramework, "/lockPath");
//try to get lock.
if(lock.acquire(5,TimeUnit.SECONDS)) {
try {
//todo 模拟业务操作
Thread.sleep(2000);
return "create order finished!";
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.release();
}
}
return "error to create lock!";
}
福利来了,京东618无门槛红包,速抢,亲测可用!!!