目录
zookeper从设计模式角度来理解:是一个基 于观察者模式设计的分布式服务管理框架,它负 责 存储和管理大家都关心的数据,然 后接受观察者的 注 册,一旦这些数据的状态发生变化,Zookeeper 就 将负责通知已经在Zookeeper上注册的那些观察 者做出相应的反应。
案例1:服务器动态上下线
服务端代码:
package com.yangmin.zkcase1;
import org.apache.zookeeper.*;
import java.io.IOException;
public class DistributeServer {
private String connectString = "master:2181,slave01:2181,slave02:2181";
private int sessionTimeout = 300000;
private ZooKeeper zk;
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
DistributeServer server = new DistributeServer();
// 1. 获取zk连接
server.getConnect();
// 2. 注册服务器到zk集群
server.regist(args[0]);
// 3. 启动业务逻辑
server.business(args[0]);
}
private void business(String hostname) throws InterruptedException {
System.out.println(hostname + " is working ...");
Thread.sleep(Long.MAX_VALUE);
}
private void regist(String hostname) throws KeeperException, InterruptedException {
String creat = zk.create("/servers/" + hostname, hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(hostname + "is online");
}
private void getConnect() throws IOException {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
}
});
}
}
客户端代码:
package com.yangmin.zkcase1;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class DistributeClient {
private static String connectString = "master:2181,slave01:2181,slave02:2181";
private static int sessionTimeout = 300000;
private ZooKeeper zk = null;
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
DistributeClient client = new DistributeClient();
// 1. 获取zk连接
client.getConnect();
// 2. 监听servers下面子节点的变化
client.getServerList();
// 3. 业务逻辑
client.business();
}
private void business() throws InterruptedException {
System.out.println("-----is working----------");
Thread.sleep(Long.MAX_VALUE);
}
private void getServerList() throws KeeperException, InterruptedException {
List<String> children = zk.getChildren("/servers", true);
ArrayList<String> servers = new ArrayList<String>();
for (String child : children) {
byte[] data = zk.getData("/servers/" + child, false, null);
servers.add(new String(data));
}
// 打印
System.out.println(servers);
}
private void getConnect() throws IOException {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
try {
getServerList();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
案例二:分布式锁的
什么叫做分布式锁呢? 比如说"进程 1"在使用该资源的时候,会先去获得锁,"进程 1"获得锁以后会对该资源保持独占,这样其他进程就无法访问该资源,"进程 1"用完该资源以后就将锁释放掉,让其 他进程来获得锁,那么通过这个锁机制,我们就能保证了分布式系统中多个进程能够有序的 访问该临界资源。那么我们把这个分布式环境下的这个锁叫作分布式锁。
方法1:使用JAVA api的方式
package com.yangmin.zkcase2;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class DistributedLock {
private final int sesionTimeout = 30000;
private final String connectString = "master:2181,slave01:2181,slave02:2181";
private final ZooKeeper zk;
private CountDownLatch connectLatch = new CountDownLatch(1);
private CountDownLatch waitLatch = new CountDownLatch(1);
private String waitPath;
private String currentNode;
public DistributedLock() throws IOException, InterruptedException, KeeperException {
// 获取连接
zk = new ZooKeeper(connectString, sesionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
// connectLatch 如果连接上 可以释放
if (watchedEvent.getState() == Event.KeeperState.SyncConnected){
connectLatch.countDown();
}
// waitLatch 需要释放
if (watchedEvent.getType() == Event.EventType.NodeDeleted && watchedEvent.getPath().equals(waitPath)){
waitLatch.countDown();
}
}
});
// 等待zk正常连接后,程序往下走
connectLatch.await();
// 判断节点/locks是否存在
Stat stat = zk.exists("/locks", false);
if (stat == null) {
zk.create("/locks", "locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
}
// 对zk加锁
public void zkLock() {
try {
currentNode = zk.create("/locks/" + "seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
// 判断创建的节点是否是最小序号节点,如果是获取到锁,如果不是,监听他序号前一个节点
List<String> children = zk.getChildren("/locks", false);
// 如果children只有一个值,直接获得该锁
if (children.size() == 1) {
return;
} else {
Collections.sort(children);
// 获取当前节点
String thisNode = currentNode.substring("/locks/".length());
int index = children.indexOf(thisNode);
if (index == -1) {
System.out.println("数据异常");
} else if (index == 0) {
return;
}else {
// 需要监听 他前一个节点
waitPath = "/locks/" + children.get(index - 1);
zk.getData(waitPath,true,null);
// 等待监听
waitLatch.await();
return;
}
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 释放锁
public void zkUnlock() {
try {
zk.delete(this.currentNode, -1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试:
package com.yangmin.zkcase2;
import org.apache.zookeeper.KeeperException;
import java.io.IOException;
public class DistributedLockTest {
public static void main(String[] args) throws InterruptedException, IOException, KeeperException {
final DistributedLock lock1 = new DistributedLock();
final DistributedLock lock2 = new DistributedLock();
new Thread(new Runnable() {
@Override
public void run() {
try {
lock1.zkLock();
System.out.println("线程1启动,获取到锁");Thread.sleep(5 * 1000);
lock1.zkUnlock();
System.out.println("线程1启动,释放锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
lock2.zkLock();
System.out.println("线程2启动,获取到锁");Thread.sleep(5 * 1000);
lock2.zkUnlock();
System.out.println("线程2启动,释放锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
方法二: Curator 框架实现分布式锁案例
package com.yangmin.zkcase3;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMultiLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class CuratorLockTest {
private static String rootNode = "/locks";
public static void main(String[] args) {
// 创建分布式锁1
final InterProcessMutex lock1 = new InterProcessMutex(getCuratorFramework(),rootNode);
// 创建分布式锁2
final InterProcessMutex lock2 = new InterProcessMutex(getCuratorFramework(),rootNode);
new Thread(new Runnable() {
@Override
public void run() {
try {
lock1.acquire();
System.out.println("线程1 获取到锁");
lock1.acquire();
System.out.println("线程1 再次获取到锁");
Thread.sleep(5 * 1000);
lock1.release();
System.out.println("线程1 释放锁");
lock1.release();
System.out.println("线程1 再次释放锁");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
lock2.acquire();
System.out.println("线程2 获取到锁");
lock2.acquire();
System.out.println("线程2 再次获取到锁");
Thread.sleep(5 * 1000);
lock2.release();
System.out.println("线程2 释放锁");
lock2.release();
System.out.println("线程2 再次释放锁");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
// 创建客户端
public static CuratorFramework getCuratorFramework() {
RetryPolicy retry = new ExponentialBackoffRetry(30000, 3);
CuratorFramework client = CuratorFrameworkFactory.builder().connectString("master:2181,slave01:2181,slave02:2181").connectionTimeoutMs(20000)
.sessionTimeoutMs(30000).retryPolicy(retry).build();
// 启动客户端
client.start();
return client;
}
}