什么是ZooKeeper
ZooKeeper是一个分布式开源框架,提供了协调分布式应用的基本服务,它向外部应用暴露一组通用服务——分布式同步(Distributed Synchronization)、命名服务(Naming Service)、集群维护(Group Maintenance)等,简化分布式应用协调及其管理的难度,提供高性能的分布式服务。ZooKeeper本身可以以单机模式安装运行,不过它的长处在于通过分布式ZooKeeper集群(一个Leader,多个Follower),基于一定的策略来保证ZooKeeper集群的稳定性和可用性,从而实现分布式应用的可靠性。
1、ZooKeeper是为别的分布式程序服务的
2、ZooKeeper本身就是一个分布式程序(只要有半数以上节点存活,zk就能正常服务)
3、ZooKeeper所提供的服务涵盖:主从协调、服务器节点动态上下线、统一配置管理、分布式共享锁、统> 一名称服务等
4、虽然说可以提供各种服务,但是ZooKeeper在底层其实只提供了两个功能:
管理(存储,读取)用户程序提交的数据(类似namenode中存放的metadata); 并为用户程序提供数据节点监听服务;
ZooKeeper的特性
1、ZooKeeper:一个leader,多个follower组成的集群
2、全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的
3、分布式读写,更新请求转发,由leader实施
4、更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
5、数据更新原子性,一次数据更新要么成功,要么失败
6、实时性,在一定时间范围内,client能读到最新数据
ZooKeeper的数据结构
在ZooKeeper内部数据结构是类似树状的文件层析结构,每个节点包含唯一的节点名称,以及可以对该节点做值的存储。ZooKeeper的节点有四种类型。
分别是临时节点、临时顺序节点、持久节点以及持久顺序节点。
持久节点可看作是将节点存储在硬盘上。
顺序节点会在node节点附加一个值,可以实现排序功能。
而临时节点则是当ZooKeeper连接关闭后自动删除该节点,这也就是实现分布式锁的关键。
ZooKeeper的应用场景
1、分布式锁
这个主要得益于ZooKeeper 为我们保证了数据的强一致性。锁服务可以分为两类,一个是 保持独占,另一个是 控制时序。
2、在dubbo官方文档中指定的注册中心就是ZooKeeper 。
3、数据发布与订阅(配置中心)
发布与订阅模型,即所谓的配置中心,顾名思义就是发布者将数据发布到ZK节点上,供订阅者动态获取数据,实现配置信息的集中式管理和动态更新。例如全局的配置信息,服务式服务框架的服务地址列表等就非常适合使用。
4、负载均衡
这里说的负载均衡是指软负载均衡。在分布式环境中,为了保证高可用性,通常同一个应用或同一个服务的提供方都会部署多份,达到对等服务。而消费者就须要在这些对等的服务器中选择一个来执行相关的业务逻辑,其中比较典型的是消息中间件中的生产者,消费者负载均衡。
接下来开始对分布式锁的实现(代码演示)
package neu.zookeeper;
/*
* 定义分布式锁
*/
public interface ZKlock {
public void lock();
public void unLock();
}
//重构重复代码,将重复代码交给子类执行
public abstract class ZookeeperAbstractLock implements ZKlock {
//是在本机windows客户端安装的Zookeeper
private static final String CONNECTSTRING = "localhost:2181";
// 创建zk连接
protected ZkClient zkClient = new ZkClient(CONNECTSTRING);
protected static final String PATH = "/lock";
protected CountDownLatch countDownLatch = null;
public void lock() {
if (getLock()) {
System.out.println("###获取锁成功#####");
} else {
// 等待
wait();
// 重新获取锁
lock();
}
}
// 是否获取锁成功,成功返回true 失败返回fasle
abstract Boolean getLock();
// 等待
abstract void wait();
@Override
public void unLock() {
if (zkClient != null) {
zkClient.close();
System.out.println("释放锁资源");
}
}
public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock {
@Override
Boolean getLock() {
try {
//试图创建一个PATH的临时节点,该节点不需要有值,为null即可
zkClient.createEphemeral(PATH);
//如果创建成功,则返回true,由于节点的唯一性,也保证了在连接没有关闭的情况下不会创建第二次
return true;
} catch (Exception e) {
return false;
}
}
@Override
void wait() {
// 使用事件监听,获取到节点被删除,
IZkDataListener iZkDataListener = new IZkDataListener() {
// 当节点被删除
public void handleDataDeleted(String dataPath) throws Exception {
if (countDownLatch != null) {
// 唤醒
countDownLatch.countDown();
}
}
// 当节点发生改变
public void handleDataChange(String dataPath, Object data) throws Exception {
}
};
// 注册节点信息
zkClient.subscribeDataChanges(PATH, iZkDataListener);
if (zkClient.exists(PATH)) {
// 创建信号量
countDownLatch = new CountDownLatch(1);
try {
// 等待
countDownLatch.await();
} catch (Exception e) {
e.printStackTrace();
}
}
// 删除事件通知
zkClient.unsubscribeDataChanges(PATH, iZkDataListener);
}
}
--------------------------------------------------------------------------------------------------------------------Java 学习新手,如果有问题还希望各位多多指教!
下一次不定期更新Zookeeper 的其他应用场景。
感谢阅读!
网友评论