基于zookeeper的分布式Queue

       原理: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,否则返回 true
				boolean 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);// 也会触发NodeChildrenChanged
					return 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 block
			e.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 block
				e.printStackTrace();
			}
		}
		return orderedChildren;
	}

	/**
	 * Watcher是一次性,只会触发一次process,除非多次设置zookeeper.getChildren(dir, watcher)
	 * 
	 * @author zero
	 *
	 */
	private class LatchChildWatcher implements Watcher {
		private volatile boolean isNotify = false;

		@Override
		public 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;
				}
			}
		}
	}
}









你可能感兴趣的:(基于zookeeper的分布式Queue)