一、简介
Zookeeper是一个分布式开源框架,提供了协调分布式应用的基本服务,它向外部应用暴露一组通用服务——分布式同步(Distributed Synchronization)、命名服务(Naming Service)、集群维护(Group Maintenance)等,简化分布式应用协调及其管理的难度,提供高性能的分布式服务
1、zk原理
1、数据结构类似于xml的树状结构
2、每个节点称为znode,包含节点名称(唯一),节点数据,子节点
2、znode类型
临时节点:连接关闭后失效
临时顺序节点:
持久节点:节点信息持久化
持久顺序节点:
二、zk环境搭建
1、windows环境
1、启动
问题:点击zkServer.cmd后一闪而过
原因:conf目录下不存在zoo.cfg文件,将实例文件改名
3.5.5版本启动一闪而过问题,除了上述那个,需下载带bin的tar包,否则只是源码
![]()
2、客户端连接
点击zkCli.cmd
3、客户端常用命令
ls /:查看根节点信息
create /mytest znode_content:创建mytest节点,节点内容为znode_content ,默认创建的是持久节点
set /mytest test_content_other:修改mytest节点内容
2、java操作zk
1、事件状态对应事件类型
![]()
2、创建持久节点
![]()
3、zk事件通知watcher
|
// 增加持久节点 public boolean createPersistentNode(String path, String data) { try { //新增订阅该节点的事件通知,也可查看该节点是否存在。针对该zk连接订阅通知 zk.exists(path, true); String result = zk.create(path, data.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println("create node: " + result); return true; } catch (KeeperException | InterruptedException e) { e.printStackTrace(); return false; }
}
@Override public void process(WatchedEvent event) { KeeperState state = event.getState(); if (state == KeeperState.SyncConnected) { EventType type = event.getType(); if (type == EventType.None) { count.countDown(); System.out.println("zk 连接成功"); } else if (type == EventType.NodeCreated) { System.out.println("事件通知,创建节点:" + event.getPath()); } else if (type == EventType.NodeDataChanged) { System.out.println("事件通知,节点数据修改:" + event.getPath()); } }
}
|
三、zk实现分布式锁
1、分布式锁解决方案
1、数据库实现分布式锁,问题:连接断开无法解锁
2、使用缓存,问题:连接断开无法马上解锁
3、使用zk实现分布式锁
2、zk分布式锁原理
使用临时节点 + 事件通知
|
import java.util.concurrent.CountDownLatch;
import org.I0Itec.zkclient.ZkClient;
public abstract class ZKAbstractLock implements Lock {
public static final String ADDRESS = "127.0.0.1:2181"; protected ZkClient zkClient = new ZkClient(ADDRESS); public static final String LOCK_PATH = "/lock"; protected CountDownLatch countDownLatch = null;
@Override public void getLock() { if (tryLock()) { System.out.println("===获取锁成功==="); } else { waitLock(); getLock(); }
}
public abstract boolean tryLock();
public abstract void waitLock();
@Override public void unLock() { if (zkClient != null) { zkClient.close(); System.out.println("===释放锁成功==="); }
}
}
=====================================================
import java.util.concurrent.CountDownLatch;
import org.I0Itec.zkclient.IZkDataListener;
public class ZKDistributeLock extends ZKAbstractLock {
@Override public boolean tryLock() { try { zkClient.createEphemeral(LOCK_PATH); return true; } catch (Exception e) { return false; } }
@Override public void waitLock() { //定义监听事件操作 IZkDataListener iZkDataListener = new IZkDataListener() { @Override public void handleDataDeleted(String dataPath) throws Exception { countDownLatch.countDown(); } @Override public void handleDataChange(String dataPath, Object data) throws Exception { // TODO Auto-generated method stub } }; //该连接注册监听 zkClient.subscribeDataChanges(LOCK_PATH, iZkDataListener); if (zkClient.exists(LOCK_PATH)) { countDownLatch = new CountDownLatch(1); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } zkClient.unsubscribeDataChanges(LOCK_PATH, iZkDataListener); }
}
=========================================================测试
mport test002_lock.OrderNumGenerator; import test003.Lock; import test003.ZKDistributeLock;
public class OrderService implements Runnable {
OrderNumGenerator orderNumGenerator = new OrderNumGenerator(); private Lock lock = new ZKDistributeLock();
@Override public void run() { try { lock.getLock(); getNumber(); } catch (Exception e) {
} finally { lock.unLock(); }
}
public String getNumber() { String num = orderNumGenerator.genNum(); System.out.println(Thread.currentThread().getName() + " 获取订单号:" + num); return num; }
public static void main(String[] args) { // OrderService orderService = new OrderService(); for (int i = 0; i < 100; i++) { new Thread(new OrderService()).start(); } } }
|
4、zk实现负载均衡
通过某节点下的所有临时子节点,获得集群信息,轮询算法进行负载均衡。