ZooKeeper实现分布式队列Queue

ZooKeeper是一个分步式的协作系统,何为协作,ZooKeeper价值又有何体现。关于ZooKeeper的基本使用,请参考:ZooKeeper伪分步式集群安装及java编程命令操作

目录

  • 分布式队列
  • 设计思路
  • 程序实现
1. 分布式队列

队列有很多种产品,大都是消息系统所实现的,像ActiveMQ,JBossMQ,RabbitMQ,IBM-MQ等。分步式队列产品并不太多,像Beanstalkd。

本文实现的分布式对列,是基于ZooKeeper现实的一种同步的分步式队列,当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达。

2. 设计思路

创建一个父目录 /queue,每个成员都监控(Watch)标志位目录/queue/start 是否存在,然后每个成员都加入这个队列,加入队列的方式就是创建 /queue/x(i)的临时目录节点,然后每个成员获取 /queue 目录的所有目录节点,也就是 x(i)。判断 i 的值是否已经是成员的个数,如果小于成员个数等待 /queue/start 的出现,如果已经相等就创建 /queue/start。

产品流程图

应用实例

图标解释

  • app1,app2,app3,app4是4个独立的业务系统
  • zk1,zk2,zk3是ZooKeeper集群的3个连接点
  • /queue,是znode的队列,假设队列长度为3
  • /queue/x1,是znode队列中,1号排对者,由app1提交,同步请求,app1挂载等待
  • /queue/x2,是znode队列中,2号排对者,由app2提交,同步请求,app2挂起等待
  • /queue/x3,是znode队列中,3号排对者,由app3提交,同步请求,app3挂起等待
  • /queue/start,当znode队列中满了,触发创建开始节点
  • 当/qeueu/start被创建后,app4被启动,所有zk的连接通知同步程序(红色线),队列已完成,所有程序结束

注:

  • 1). 创建/queue/x1,/queue/x2,/queue/x3没有前后顺序,提交后程序就同步挂起。
  • 2). app1可以通过zk2提交,app2也可通过zk3提交
  • 3). app1可以提交3次请求,生成x1,x2,x3使用队列充满
  • 4). /queue/start被创建后,zk1会监听到这个事件,再告诉app1,队列已完成!
详细代码实现:
  1. import java.io.IOException;

  2. import org.apache.zookeeper.CreateMode;
  3. import org.apache.zookeeper.KeeperException;
  4. import org.apache.zookeeper.WatchedEvent;
  5. import org.apache.zookeeper.Watcher;
  6. import org.apache.zookeeper.ZooKeeper;
  7. import org.apache.zookeeper.ZooDefs.Ids;

  8. public class QueueZooKeeper {

  9.     public static void main(String[] args) throws Exception {
  10.         if (args.length == 0) {
  11.             doOne();
  12.         } else {
  13.             doAction(Integer.parseInt(args[0]));
  14.         }
  15.     }

  16.     public static void doOne() throws Exception {
  17.         String host1 = "192.168.1.201:2181";
  18.         ZooKeeper zk = connection(host1);
  19.         initQueue(zk);
  20.         joinQueue(zk, 1);
  21.         joinQueue(zk, 2);
  22.         joinQueue(zk, 3);
  23.         zk.close();
  24.     }

  25.     public static void doAction(int client) throws Exception {
  26.         String host1 = "192.168.1.201:2181";
  27.         String host2 = "192.168.1.201:2182";
  28.         String host3 = "192.168.1.201:2183";

  29.         ZooKeeper zk = null;
  30.         switch (client) {
  31.         case 1:
  32.             zk = connection(host1);
  33.             initQueue(zk);
  34.             joinQueue(zk, 1);
  35.             break;
  36.         case 2:
  37.             zk = connection(host2);
  38.             initQueue(zk);
  39.             joinQueue(zk, 2);
  40.             break;
  41.         case 3:
  42.             zk = connection(host3);
  43.             initQueue(zk);
  44.             joinQueue(zk, 3);
  45.             break;
  46.         }
  47.     }

  48.     // 创建一个与服务器的连接
  49.     public static ZooKeeper connection(String host) throws IOException {
  50.         ZooKeeper zk = new ZooKeeper(host, 60000, new Watcher() {
  51.             // 监控所有被触发的事件
  52.             public void process(WatchedEvent event) {
  53.                 if (event.getType() == Event.EventType.NodeCreated && event.getPath().equals("/queue/start")) {
  54.                     System.out.println("Queue has Completed.Finish testing!!!");
  55.                 }
  56.             }
  57.         });
  58.         return zk;
  59.     }

  60.     public static void initQueue(ZooKeeper zk) throws KeeperException, InterruptedException {
  61.         System.out.println("WATCH => /queue/start");
  62.         zk.exists("/queue/start", true);

  63.         if (zk.exists("/queue", false) == null) {
  64.             System.out.println("create /queue task-queue");
  65.             zk.create("/queue", "task-queue".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
  66.         } else {
  67.             System.out.println("/queue is exist!");
  68.         }
  69.     }

  70.     public static void joinQueue(ZooKeeper zk, int x) throws KeeperException, InterruptedException {
  71.         System.out.println("create /queue/x" + x + " x" + x);
  72.         zk.create("/queue/x" + x, ("x" + x).getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
  73.         isCompleted(zk);
  74.     }

  75.     public static void isCompleted(ZooKeeper zk) throws KeeperException, InterruptedException {
  76.         int size = 3;
  77.         int length = zk.getChildren("/queue", true).size();

  78.         System.out.println("Queue Complete:" + length + "/" + size);
  79.         if (length >= size) {
  80.             System.out.println("create /queue/start start");
  81.             zk.create("/queue/start", "start".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
  82.         } 
  83.     }

  84. }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值