1.使用Zookeeper作为注册中心
Zookeeper可以用作配置中心,当我们的配置发生变化时,可以通知客户端,更新配置信息
Zookeeper配置中心的原理:
( 1)连接zookeeper服务器
(2)读取zookeeper中的配置信息,注册watcher监听器,存入本地变量
(3)当zookeeper中的配置信息发生变化时,通过watcher的回调方法捕获数据变化事件
(4)重新获取配置信息
public class c12作为配置中心 implements Watcher {
String ip = "mymv:2181";
CountDownLatch countDownLatch = new CountDownLatch(1);
static ZooKeeper zooKeeper;
//本地化配置信息
private String url;
private String username;
private String password;
@Override
public void process(WatchedEvent event) {
try {
// 捕获事件状态
if (event.getType() == Event.EventType.None) {
if (event.getState() == Event.KeeperState.SyncConnected)
{
System.out.println("连接成功");
countDownLatch.countDown();
} else if (event.getState() == Event.KeeperState.Disconnected) {
System.out.println("连接断开!");
} else if (event.getState() == Event.KeeperState.Expired)
{
System.out.println("连接超时!");
// 超时后服务器端已经将连接释放,需要重新连接服务器端
zooKeeper = new ZooKeeper("192.168.60.130:2181", 6000, new c12作为配置中心());
} else if (event.getState() ==
Event.KeeperState.AuthFailed) {
System.out.println("验证失败!");
}
// 当配置信息发生变化时
} else if (event.getType() == Event.EventType.NodeDataChanged) {
initValue();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 构造方法
public c12作为配置中心() {
initValue();
}
// 连接zookeeper服务器,读取配置信息
public void initValue() {
try {
// 创建连接对象
zooKeeper = new ZooKeeper(ip, 5000, this);
// 阻塞线程,等待连接的创建成功
countDownLatch.await();
// 读取配置信息
this.url = new String(zooKeeper.getData("/config/url", true, null));
this.username = new String(zooKeeper.getData("/config/username", true, null));
this.password = new String(zooKeeper.getData("/config/password", true, null));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
c12作为配置中心 configCenter = new c12作为配置中心();
try{
for (int i = 1; i <= 20; i++) {
Thread.sleep(5000);
System.out.println("url:" + configCenter.getUrl());
System.out.println("username:" + configCenter.getUsername());
System.out.println("password:" + configCenter.getPassword());
System.out.println("########################################");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public String getUrl() {
return url;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
2.生成唯一的分布式ID
在对数据库进行分表操作时候,需要保证我们的数据在不同的表中拥有唯一的id,通过Zookeeper的序列化临时节点,可以完成全局唯一id的生成
原理: (1)连接zookeeper服务器 (2)指定路径生成临时有序节点 (3)取序列号及为分布式环境下的唯一ID
public class c13生成唯一id implements Watcher {
String ip = "mymv:2181";
CountDownLatch countDownLatch =new CountDownLatch(1);
ZooKeeper zooKeeper;
@Override
public void process(WatchedEvent event) {
try {
// 捕获事件状态
if (event.getType() == Event.EventType.None) {
if (event.getState() == Event.KeeperState.SyncConnected)
{
System.out.println("连接成功");
countDownLatch.countDown();
} else if (event.getState() == Event.KeeperState.Disconnected) {
System.out.println("连接断开!");
} else if (event.getState() == Event.KeeperState.Expired)
{
System.out.println("连接超时!");
// 超时后服务器端已经将连接释放,需要重新连接服务器端
zooKeeper = new ZooKeeper(ip, 6000, new c12作为配置中心());
} else if (event.getState() ==
Event.KeeperState.AuthFailed) {
System.out.println("验证失败!");
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public c13生成唯一id() {
try {
//打开连接
zooKeeper = new ZooKeeper(ip, 5000, this);
// 阻塞线程,等待连接的创建成功
countDownLatch.await();
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 生成id的方法
public String getUniqueId() {
String path = "";
try {
//创建临时有序节点
path = zooKeeper.create("/uniuqeId", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
} catch (Exception ex) {
ex.printStackTrace();
}
return path.substring(9);
}
public static void main(String[] args) {
c13生成唯一id unique = new c13生成唯一id();
for (int i = 0; i < 10; i++) {
System.out.println(unique.getUniqueId());
}
}
}
3.分布式锁
通过zookeeper的有序节点,可以实现分布式锁
实现排它锁原理:
(1)每个客户端往/Locks下创建临时有序节点/Locks/Lock000000001
(2)客户端取得/Locks下子节点,并进行排序,判断排在最前面的是否为自己,如果自己的锁节点在第一位,代表获取锁成功
(3)如果自己的锁节点不在第一位,则监听自己前一位的锁节点。
(4)当前一位锁节点的状态发生变化时,会通知监听客户端重新执行第2步逻辑,判断自己是否获得了锁
实现共享锁原理:
(1)每个客户端往/Locks下创建临时有序节点/Locks/Lock000000001,并指明节点的内容为R,或者W
(2)客户端取得/Locks下子节点,并进行排序,判断排在最前面的是否为自己,如果自己的锁节点在第一位,代表获取锁成功
(3)如果自己的锁节点不在第一位,则查看比自己小的节点是否都为R,如果为R,则可以获取锁,否者则监听自己前一位的锁节点。
(4)当前一位锁节点的状态发生变化时,会通知监听客户端重新执行第2步逻辑,判断自己是否获得了锁
public class c14分布式锁 implements Watcher {
String ip = "mymv:2181";
CountDownLatch countDownLatch =new CountDownLatch(1);
ZooKeeper zooKeeper;
private static final String LOCK_ROOT_PATH = "/Locks";
private static final String LOCK_NODE_NAME = "Lock_";
private String lockPath;
@Override
public void process(WatchedEvent event) {
try {
// 捕获事件状态
if (event.getType() == Watcher.Event.EventType.None) {
if (event.getState() == Watcher.Event.KeeperState.SyncConnected)
{
System.out.println("连接成功");
countDownLatch.countDown();
} else if (event.getState() == Watcher.Event.KeeperState.Disconnected) {
System.out.println("连接断开!");
} else if (event.getState() == Watcher.Event.KeeperState.Expired)
{
System.out.println("连接超时!");
// 超时后服务器端已经将连接释放,需要重新连接服务器端
zooKeeper = new ZooKeeper(ip, 6000, new c12作为配置中心());
} else if (event.getState() ==
Watcher.Event.KeeperState.AuthFailed) {
System.out.println("验证失败!");
}
}else if (event.getType() == Event.EventType.NodeDeleted) {
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public c14分布式锁() {
try {
//打开连接
zooKeeper = new ZooKeeper(ip, 500000, this);
// 阻塞线程,等待连接的创建成功
countDownLatch.await();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void acquireLock() throws Exception {
//创建锁节点
createLock();
//尝试获取锁
attemptLock();
}
//创建锁节点
private void createLock() throws Exception {
//判断Locks是否存在,不存在创建
Stat stat = zooKeeper.exists(LOCK_ROOT_PATH, false);
if (stat == null) {
zooKeeper.create(LOCK_ROOT_PATH, new byte[0],
ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
// 创建临时有序节点
lockPath = zooKeeper.create(LOCK_ROOT_PATH + "/" + LOCK_NODE_NAME,
new byte[0],
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println("节点创建成功:" + lockPath);
}
//尝试获取锁
private void attemptLock() throws Exception {
// 获取Locks节点下的所有子节点
List<String> list = zooKeeper.getChildren(LOCK_ROOT_PATH, false);
// 对子节点进行排序
Collections.sort(list);
// /Locks/Lock_000000001
int index = list.indexOf(lockPath.substring(LOCK_ROOT_PATH.length() + 1));
if (index == 0) {
System.out.println("获取锁成功!");
return;
} else {
// 上一个节点的路径
String path = list.get(index - 1);
Stat stat = zooKeeper.exists(LOCK_ROOT_PATH + "/" + path, this);
if (stat == null) {
attemptLock();
} else {
synchronized (this) {
this.wait();
}
attemptLock();
}
}
}
//释放锁
public void releaseLock() throws Exception {
//删除临时有序节点
zooKeeper.delete(this.lockPath,-1);
zooKeeper.close();
System.out.println("锁已经释放:"+this.lockPath);
}
public static void main(String[] args) {
try {
c14分布式锁 myLock = new c14分布式锁();
myLock.acquireLock();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}