使用zookeeper一个简单分布式demo

来源:互联网 发布:什么软件ktv便宜 编辑:程序博客网 时间:2024/06/06 00:31

zookeeper是一个提供分布式程序协调服务的应用,它的命名空间类似linux系统文件路径等等。 具体描述可以参考官网 https://zookeeper.apache.org/doc/trunk/zookeeperOver.html

本文将描述如何借助zookeeper构建一个简单的任务发布运行应用,使用curator。(我也是刚接触zk,如有不对的地方希望指出.谢谢)

设计

我将任务发布部分作为server,任务处理部分作为client

server部分

server部分功能比较简单。主要进行任务的发布。
首先server启动时向zk创建节点/test ,为持久节点

http://or0f3pi7r.bkt.clouddn.com/17-10-22/64173110.jpg

之后我们向server提交任务,假设任务名称为localtask,数据为hello worldserver会向zk/test节点下注册新的任务节点,这是一个持久节点,以任务名作为节点名,任务的数据存放在节点内。

http://or0f3pi7r.bkt.clouddn.com/17-10-22/52451648.jpg

client部分

client部分主要接收任务,并允许任务。同时一旦某个运行任务所在的机器挂掉,其它机器能够接管该任务。下面以一个client为例来介绍。

client启动时会向zk添加对/test节点的listener

http://or0f3pi7r.bkt.clouddn.com/17-10-22/82030185.jpg

server发布任务后,client能够监听任务节点的创建

http://or0f3pi7r.bkt.clouddn.com/17-10-22/46068484.jpg

client发现新任务时,首先会对该任务节点添加子节点变化的listener,之后会尝试对任务加锁,加锁成功的客户端能够运行任务。
如何进行加锁: 创建任务节点的子节点/lock,这是一个临时节点。 因为zookeeper会保证多个客户端同时创建同一个节点,只有一客户端能够创建成功。当某台机器宕机,那么就与zk失去了心跳,那么该临时节点就会被删除,那么其它节点会尝试去加锁。

http://or0f3pi7r.bkt.clouddn.com/17-10-22/45733300.jpg

如果/lock节点创建成功,则表示当前客户端获得了运行任务的权利。客户端开始启动任务

http://or0f3pi7r.bkt.clouddn.com/17-10-22/47504175.jpg

代码实现

这里只给出部分代码,全部代码
https://github.com/sweat123/distribute_cluster

server实现

创建任务根节点

    public void start() {        if (!nodeExists(ROOT)) {            try {                zkClient.create().creatingParentsIfNeeded().withMode(PERSISTENT).forPath(ROOT);            } catch (Exception e) {                LOG.error("create root failed.", e);            }        }    }

创建任务

    public void createTask(String taskName, byte[] data) {        String path = ROOT + "/" + taskName;        if (nodeExists(path)) {            LOG.error("task already exists.");            return;        }        try {            zkClient.create().withMode(PERSISTENT).forPath(path, data);        } catch (Exception e) {            LOG.error("create task failed. node path: {}", path, e);        }    }

client实现

添加对任务根节点的listener

    public void registry() throws Exception {        PathChildrenCache childrenCache = new PathChildrenCache(zkClient, ROOT, true);        childrenCache.start();        childrenCache.getListenable().addListener((client, event) -> {            switch (event.getType()) {            case CHILD_ADDED:                LOG.info("child add; node path: {}", event.getData().getPath());                lockAndWork(client, event);                addLockListener(client, event.getData().getPath());                break;            case CHILD_REMOVED:                LOG.info("child removed; node path: {}", event.getData().getPath());                break;            }        });    }

server任务发布后,创建对任务节点的listener,并尝试对任务加锁,如果加锁成功则运行任务

    private boolean tryLock(CuratorFramework zkClient, String path) {        try {            zkClient.create().withMode(EPHEMERAL).forPath(path);        } catch (Exception e) {            LOG.error("create node failed; node path: {}", path, e);            return false;        }        return true;    }    private void lockAndWork(CuratorFramework zkClient, PathChildrenCacheEvent event) {        String path = event.getData().getPath();        byte[] nodeData = event.getData().getData();        if (!tryLock(zkClient, path + "/lock")) {            LOG.info("lock node failed.");            return;        }        //lock succeed        createTask(nodeData);    }    private void createTask(byte[] data) {        String dataStr = Utils.convertJsonByteArrToAssignedObj(data, "key", String.class);        LOG.info("create task with data {}", dataStr);    }
原创粉丝点击