Zookeeper数据结构
- ZooKeeper数据模型的结构与Unix文件系统很类似,整体上可以看作是一棵树,每个节点称做一个ZNode。每个Znode可以类似看作是一个目录,其下可以创建子目录。很显然zookeeper集群自身维护了一套数据结构。这个存储结构是一个树形结构,其上的每一个节点,我们称之为"znode",每一个znode默认能够存储1MB的数据,每个ZNode都可以通过其路径唯一标识。
- Zookeeper 节点类型可以分为三大类:持久性节点(Persistent)、临时性节点(Ephemeral)、顺序性节点(Sequential)。
Zookeeper的观察器
- 在Zookeeper中可以设置观察器的3个方法:
- 1.getData() 获取数据
- 2.getChilderen() 获取子节点
- 3.exists() 判断当前节点是否存在
- 通过在Zookeeper中设置观察器,节点数据发生变化,发送给客户端。观察器只能监控一次,在监控需要重新设置 ,但是本次我们使用zookeeper的升级版(curator),可以解决监控一次的问题。
Zookeeper实现原理
- 利用Zookeeper的瞬时有序节点的特性,在多线程并发创建瞬时节点的时候,得到有序的序列,序号最小的线程获得锁。其他获得锁的线程都是失败的。其他线程只能监听自己序号的前一个序号,前一个序号执行完成以后,删除自己序号的节点,下一个序号的线程得到通知,接着执行。所以创建节点的时候,已经确定了线程的执行顺序按照序号去执行。
代码实现
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
</dependency>
import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
@Slf4j
public class ZkLock implements AutoCloseable, Watcher {
private ZooKeeper zooKeeper;
private String znode;
public ZkLock() throws IOException {
this.zooKeeper = new ZooKeeper("localhost:2181",
10000,this);
}
public boolean getLock(String businessCode) {
try {
Stat stat = zooKeeper.exists("/" + businessCode, false);
if (stat==null){
zooKeeper.create("/" + businessCode,businessCode.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
znode = zooKeeper.create("/" + businessCode + "/" + businessCode + "_", businessCode.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
List<String> childrenNodes = zooKeeper.getChildren("/" + businessCode, false);
Collections.sort(childrenNodes);
String firstNode = childrenNodes.get(0);
if (znode.endsWith(firstNode)){
return true;
}
String lastNode = firstNode;
for (String node:childrenNodes){
if (znode.endsWith(node)){
zooKeeper.exists("/"+businessCode+"/"+lastNode,true);
break;
}else {
lastNode = node;
}
}
synchronized (this){
wait();
}
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
public void close() throws Exception {
zooKeeper.delete(znode,-1);
zooKeeper.close();
log.info("我已经释放了锁!");
}
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.NodeDeleted){
synchronized (this){
notify();
}
}
}
}
@RestController
public class ZookeeperController {
@Autowired
private CuratorFramework client;
@RequestMapping("zkLock")
public String zookeeperLock(){
try (ZkLock zkLock = new ZkLock()) {
if (zkLock.getLock("order")){
Thread.sleep(10000);
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return "方法执行完成!";
}
}