基于zookeeper的分布式Queue

来源:互联网 发布:qq的smtp服务器端口 编辑:程序博客网 时间:2024/06/06 00:28
       原理:ZooKeeper通过一个Node来维护Queue的实体,用其children来存储Queue的内容,并且ZooKeeper的create方法中提供了顺序递增的模式,会自动地在name后面加上一个递增的数字来插入新元素。可以用其children来构建一个queue的数据结构,offer的时候使用create,take的时候按照children的顺序删除第一个即可。ZooKeeper保障了各个server上数据是一致的,因此也就实现了一个分布式Queue。代码如下:
package com.zero.zookeeper;import java.io.IOException;import java.util.List;import java.util.TreeMap;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.KeeperException.NoNodeException;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.EventType;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;import org.apache.zookeeper.data.Stat;public class DistributedQueue {private static DistributedQueue instance = new DistributedQueue();private static ZooKeeper zookeeper;private String dir = "/distributedQueue";private String prefix = "queueIndex";private DistributedQueue() {if (null != instance) {throw new AssertionError();}try {zookeeper = new ZooKeeper("localhost:2181", 10000, null);} catch (IOException e) {e.printStackTrace();}}public static DistributedQueue getInstanceQueue() {return instance;}public byte[] take() throws KeeperException, InterruptedException {return take(Long.MAX_VALUE);}public byte[] take(long time) throws KeeperException, InterruptedException {while (true) {LatchChildWatcher childWatcher = new LatchChildWatcher();TreeMap<Long, String> orderedChildren;try {orderedChildren = (TreeMap<Long, String>) orderChildren(childWatcher);} catch (KeeperException.NoNodeException e) {zookeeper.create(dir, new byte[0], Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);continue;}if (orderedChildren.size() == 0) {// 等待时间超时,则返回 false,否则返回 trueboolean idNotified = childWatcher.await(time);if (idNotified) {continue;}return null;}for (String childNode : orderedChildren.values()) {try {byte[] data = zookeeper.getData(childNode, false, null);zookeeper.delete(childNode, -1);// 也会触发NodeChildrenChangedreturn data;} catch (KeeperException.NoNodeException e) {}}}}/** * 将数据插入队列中 *  * @param data * @return * @throws KeeperException * @throws InterruptedException */public boolean offer(byte[] data) throws KeeperException,InterruptedException {for (;;) {try {zookeeper.create(dir + "/" + prefix, data, Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT_SEQUENTIAL);return true;} catch (KeeperException.NoNodeException e) {zookeeper.create(dir, new byte[0], Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);}}}public static void close() {try {zookeeper.close();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}private TreeMap<Long, String> orderChildren(Watcher watcher)throws NoNodeException {Stat stat = null;try {stat = zookeeper.exists(dir, true);// 这里如果加watcher,会监控dir的NodeCreated与NodeDeleted} catch (KeeperException | InterruptedException e) {e.printStackTrace();}if (stat == null) {throw new KeeperException.NoNodeException();}List<String> childernList = null;try {childernList = zookeeper.getChildren(dir, watcher);// 这里如果加watcher,会监控dir的NodeChildrenChanged} catch (KeeperException | InterruptedException e) {e.printStackTrace();}TreeMap<Long, String> orderedChildren = new TreeMap<Long, String>();for (String childNode : childernList) {try {String childNodePath = dir + "/" + childNode;Stat s = zookeeper.exists(childNodePath, true);if (s != null) {// 多线程下可能zookeeper.getChildren后childNode被删除orderedChildren.put(s.getCzxid(), childNodePath);}} catch (KeeperException | InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return orderedChildren;}/** * Watcher是一次性,只会触发一次process,除非多次设置zookeeper.getChildren(dir, watcher) *  * @author zero * */private class LatchChildWatcher implements Watcher {private volatile boolean isNotify = false;@Overridepublic void process(WatchedEvent event) {if (EventType.NodeChildrenChanged == event.getType()) {isNotify = true;}}public boolean await(long time) throws InterruptedException {long end = System.currentTimeMillis() + time * 1000;for (;;) {TimeUnit.MILLISECONDS.sleep(100);if (isNotify) {return true;} else if (System.currentTimeMillis() >= end) {return false;}}}}}









0 0