使用Zookeeper制作ID生成器

背景分析

分布式系统中,我们要保证ID唯一,一般情况下会选择UUID来作为全局唯一的ID。在需求变更时,需要有序的且唯一的全局ID,这时候我们可以考虑使用zookeeper来作为全局ID的生成器。

原理介绍

  1. zookeeper是一个分布式的,高可用的服务
  2. zookeeper自带生成顺序节点的功能,可以使用其生成顺序节点的编号来作为ID

例如一下zookeeper中顺序节点的结构
例如一下zookeeper中顺序节点的结构
每个文件节点都有一个顺序编号,每次新建顺序节点都是在上一个顺序编号上加1来作为新的顺序编号,保证了生成ID的有序。

Java客户端代码

首先我们引入zkCLient作为zookeeper的客户端,在pom.xml文件中加入

        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.10</version>
        </dependency>

下面是java代码

import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkNoNodeException;
import org.I0Itec.zkclient.serialize.BytesPushThroughSerializer;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class IdMaker {

    private ZkClient zkClient;
    //服务器地址
    private final String server;
    //根目录
    private final String root;
    //顺序节点名称
    private final String nodeName;
    //服务运行状态
    private volatile boolean running = false;

    private ExecutorService executorService;

    public enum RemoveMethod{
        NONE,IMMEDIATELY,DELAY
    }

    public IdMaker(String server, String root, String nodeName) {
        this.server = server;
        this.root = root;
        this.nodeName = nodeName;
    }

    public void start() throws Exception{
        if(running){
            throw new Exception("server is running!");
        }
        running = true;
        init();
    }

    public void stop() throws Exception{
        if(!running){
            throw new Exception("server is not running!");
        }
        running = false;
        freeResource();
    }

    private void init(){
        //实例化zookeeper对象
        zkClient = new ZkClient(server, 5000, 5000, new BytesPushThroughSerializer());
        executorService = Executors.newFixedThreadPool(10);
        try {
            zkClient.createPersistent(root, true);
        }catch (ZkNoNodeException e){
            //igore
        }
    }

    private void freeResource(){
        executorService.shutdown();
        executorService = null;
        if(zkClient != null){
            zkClient.close();
            zkClient = null;
        }
    }

    private void checkRunning() throws Exception{
        if(!running){
            throw new Exception("server is not running, please call start()");
        }
    }

    public String generateId(RemoveMethod removeMethod) throws Exception {
        checkRunning();
        final String fullNodePath = root.concat("/").concat(nodeName);
        final String ourPath = zkClient.createPersistentSequential(fullNodePath, null);

        if(removeMethod.equals(RemoveMethod.IMMEDIATELY)){
            zkClient.delete(ourPath);
        }else if(removeMethod.equals(RemoveMethod.DELAY)){
            executorService.execute(new Runnable() {
                public void run() {
                    zkClient.delete(ourPath);
                }
            });
        }


        //node-0000000001
        return extratId(ourPath);
    }

    private String extratId(String ourPath){
        int index = ourPath.indexOf(nodeName);
        if(index > 0){
            index += nodeName.length();
            return index <= ourPath.length() ? ourPath.substring(index) : "";
        }
        return ourPath;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值