您的位置:首页 > 其它

ZooKeeper 实现命名服务(分布式的ID生成器)

2016-11-29 10:19 579 查看
1、生成器类

package com.zk.zkclient.nameservice;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

import org.I0Itec.zkclient.ZkClient;

import org.I0Itec.zkclient.exception.ZkNodeExistsException;

import org.I0Itec.zkclient.serialize.BytesPushThroughSerializer;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

/**

 * Zookeeper的命名服务(ID生成器)

 *

 * @version 2016年11月29日上午9:51:37

 * @author wuliu

 */

public class IdMaker {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    

    private ZkClient client = null;

    // 服务地址

    private final String server;

    // id生成器根节点

    private final String root;

    // id节点

    private final String nodeName;

    // 启动状态: true:启动;false:没有启动,默认没有启动

    private volatile boolean running = false;

    private ExecutorService cleanExector = null;

    

    public enum RemoveMethod {

        // 不,立即,延期

        NONE, IMMEDIATELY, DELAY

    }

    

    public IdMaker(String zkServer, String root, String nodeName) {

        this.server = zkServer;

        this.root = root;

        this.nodeName = nodeName;

    }

    

    /**

     * 启动

     *

     * @version 2016年11月29日上午9:37:36

     * @author wuliu

     * @throws Exception

     */

    public void start() throws Exception {

        if (running)

            throw new Exception("server has stated...");

        running = true;

        init();

    }

    

    /**

     * 停止服务

     *

     * @version 2016年11月29日上午9:45:38

     * @author wuliu

     * @throws Exception

     */

    public void stop() throws Exception {

        if (!running)

            throw new Exception("server has stopped...");

        running = false;

        freeResource();

    }

    

    private void init() {

        client = new ZkClient(server, 5000, 5000, new BytesPushThroughSerializer());

        cleanExector = Executors.newFixedThreadPool(10);

        try {

            client.createPersistent(root, true);

        }

        catch (ZkNodeExistsException e) {

            logger.info("节点已经存在,节点路径:" + root);

        }

        

    }

    

    /**

     * 资源释放 T

     *

     * @version 2016年11月29日上午9:38:59

     * @author wuliu

     */

    private void freeResource() {

        cleanExector.shutdown();

        try {

            cleanExector.awaitTermination(2, TimeUnit.SECONDS);

        }

        catch (InterruptedException e) {

            e.printStackTrace();

        }

        finally {

            cleanExector = null;

        }

        if (client != null) {

            client.close();

            client = null;

        }

    }

    

    /**

     * 判断是否启动服务

     *

     * @version 2016年11月29日上午9:39:58

     * @author wuliu

     * @throws Exception

     */

    private void checkRunning() throws Exception {

        if (!running)

            throw new Exception("请先调用start启动服务");

    }

    

    /**

     * 提取ID

     *

     * @version 2016年11月29日上午9:46:48

     * @author wuliu

     * @param str

     * @return

     */

    private String ExtractId(String str) {

        int index = str.lastIndexOf(nodeName);// 20

        if (index >= 0) {

            index += nodeName.length();

            return index <= str.length() ? str.substring(index) : "";

        }

        return str;

    }

    

    /**

     * 获取id

     *

     * @version 2016年11月29日上午9:40:33

     * @author wuliu

     * @param removeMethod

     * @return

     * @throws Exception

     */

    public String generateId(RemoveMethod removeMethod) throws Exception {

        checkRunning();

        final String fullNodePath = root.concat("/").concat(nodeName);

        // 创建顺序节点每个父节点会为他的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序。

        // 基于这个特性,在创建子节点的时候,可以设置这个属性,那么在创建节点过程中,

        // ZooKeeper会自动为给定节点名加上一个数字后缀,作为新的节点名

        final String ourPath = client.createPersistentSequential(fullNodePath, null);

        if (removeMethod.equals(RemoveMethod.IMMEDIATELY)) {// 立即删除

            client.delete(ourPath);

        }

        else if (removeMethod.equals(RemoveMethod.DELAY)) {// 延期删除

            cleanExector.execute(new Runnable() {

                public void run() {

                    client.delete(ourPath);

                }

            });

            

        }

        return ExtractId(ourPath);

    }

    

}

2、测试

package com.zk.zkclient.nameservice;

import com.zk.zkclient.nameservice.IdMaker.RemoveMethod;

public class TestIdMaker {

    public static void main(String[] args) throws Exception {

        

        IdMaker idMaker = new IdMaker("127.0.0.1:2181",

                "/NameService/IdGen", "ID-");

        idMaker.start();

        try {

            for (int i = 0; i < 2; i++) {

                String id = idMaker.generateId(RemoveMethod.DELAY);

                System.out.println(id);

            }

        } finally {

            idMaker.stop();

        }

    }

}

3、介绍

3.1、命名服务(提供名字的服务)

zookeeper的命名服务,有两个应用方向:

            1、提供类似JNDI的功能:利用zookeeper中的树形分层结构,可以把系统中的各种服务的名称,地址以及目录信息存放在zookeeper中,

需要的时候去zookeeper中读取

            2、利用zookeeper中的顺序节点的特性,制作分布式的序列号生成器(ID生成器),(在往数据库查询数据时,通常需要一个id,在单机环境下,可以利用数据库的自动成功id号,但是这种在分布式环境下就无法使用了,可以使用UUID,但是UUID有一个缺点,就是没有规律很难理解。使用zookeeper的命名服务可以生成有顺序的容易理解的,支持分布式的编号)

架构图:



算法流程图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐