基于ZooKeeper的分布式ID生成器的示例代码

public class DistributedIdGenerator {
    private ZooKeeper zooKeeper;
    private String idNodePath;
    private String idNodePrefix;
    private AtomicInteger counter;

    public DistributedIdGenerator(ZooKeeper zooKeeper, String idNodePath, String idNodePrefix) {
        this.zooKeeper = zooKeeper;
        this.idNodePath = idNodePath;
        this.idNodePrefix = idNodePrefix;
        this.counter = new AtomicInteger(0);
    }

    public long nextId() throws KeeperException, InterruptedException {
        while (true) {
            // 创建顺序节点
            String idNode = zooKeeper.create(idNodePath + "/" + idNodePrefix, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            // 获取序号
            int seq = Integer.parseInt(idNode.substring(idNodePrefix.length()));
            // 判断是否是第一个节点
            if (seq == 0) {
                // 获取计数器的值
                int count = counter.getAndIncrement();
                // 如果计数器的值小于等于0,则说明该节点是第一个节点,可以返回ID
                if (count <= 0) {
                    // 生成ID
                    long timestamp = System.currentTimeMillis();
                    long nodeId = zooKeeper.getSessionId();
                    long id = (timestamp << 32) | nodeId;
                    return id;
                }
                // 如果计数器的值大于0,则说明该节点不是第一个节点,需要删除节点并重试
                zooKeeper.delete(idNode, -1);
            } else {
                // 获取前一个节点的名称
                String prevIdNode = idNodePath + "/" + idNodePrefix + String.format("%010d", seq - 1);
                // 判断前一个节点是否存在,如果不存在则重试
                if (zooKeeper.exists(prevIdNode, false) == null) {
                    zooKeeper.delete(idNode, -1);
                } else {
                    // 等待前一个节点被删除
                    zooKeeper.exists(prevIdNode, true);
                }
            }
        }
    }
}
 

上述代码中,使用ZooKeeper实现了一个分布式ID生成器。在构造函数中指定ZooKeeper客户端和ID节点的路径和前缀,调用nextId方法可以生成一个唯一的ID。生成ID的过程如下:

  1. 在ZooKeeper中创建一个顺序节点,节点名称为ID节点前缀加上一个数字序号。
  2. 获取该节点的数字序号,如果是第一个节点,则通过计数器判断是否可以返回ID;如果不是第一个节点,则等待前一个节点被删除。
  3. 如果可以返回ID,则根据当前时间戳和ZooKeeper的会话ID生成一个64位的long类型数据作为ID。

需要注意的是,这个实现方式并不是绝对高效,因为每个节点都需要等待前一个节点被删除才能生成ID,会有一定的等待时间。但是,由于ZooKeeper已经实现了分布式锁和顺序节点等功能,这个实现方式比较简单,并且可以保证生成的ID是全局唯一的。

猜你喜欢

转载自blog.csdn.net/yijiemuhuashi/article/details/129766792
今日推荐