zoukankan      html  css  js  c++  java
  • 分布式全局唯一ID与自增序列

    包含时间顺序的ID

    此场景最简单的实现方案,就是采用 twitter 的 Snowflake 算法。
    ID总长64位,第1位不可用,41位表示时间戳,10位表示生成机器的id,后12位表示序列号。

    • 为什么第一位不可用?第一位为0,可以确保ID在java的long类型数据一直为正整数递增
    • 同一时间戳即毫秒内,能产生多少个ID? 2^12 = 4096 个ID [ 0 ~ 4095 ]
    • 唯一性?通过机器ID预先已经做了一次空间隔离,再通过时间戳做了一次时间隔离,最后通过时间戳内的计数实现了一定程度内的唯一
    • 高性能?可以通过增加IDWorker来缓解高并发时的单机负载压力
    • 缺点?时间受限,41位可以表示69年(不过可以减少机器位来增加时间位数)

    自增序列

    原理

    根据key获取分布式锁,获得锁后取得序号,并偏移配置的偏移量,替换原先的序号,最后释放锁。

    基于zookeeper实现

    基于zookeeper可以很快实现自增序列服务,引入apache的curator封装的zookeeper客户端。

    1
    2
    3
    4
    <dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    </dependency>

    建立zookeeper连接,打开zkclient后,如果重复会使用,可以将其放入全局map中,作统一管理。

    address:zookeeper的地址
    RetryNTimes:重连策略(重连重试次数,重连间隔毫秒)

    1
    2
    CuratorFramework zkClient =  CuratorFrameworkFactory.newClient(address,new RetryNTimes(10, 5000));
    zkClient.start();

    获取分布式锁
    按照业务逻辑,选择合适的锁,此处用的是可重入共享锁,即一个客户端在拥有锁的同时,可以再请求获取。

    大专栏  分布式全局唯一ID与自增序列="gutter">
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    InterProcessMutex lock = new InterProcessMutex(zkClient, lockPath);
    try {
    if (lock.acquire(time, unit)) {
    consumer.accept(lockPath);
    return true;
    }
    return false;
    } catch (Exception e) {
    logger.error(e.getMessage(), e);
    } finally {
    try {
    lock.release();
    } catch (Exception e) {
    logger.error(e.getMessage(), e);
    }
    }
    return false;

    获取下个序号
    判断序列名称是否已经存在,如果不存在创建,存在则增加step并写入

    creatingParentsIfNeeded:当zk节点的父级不存在的时候,迭代创建
    sequenceName:序列名称
    step:自增步长

    1
    2
    3
    4
    5
    6
    7
    8
    9
    String path = "/seq/"+sequenceName;
    boolean exists = zkClient.checkExists().forPath(path) != null;
    if (!exists) {
    zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, (step + "").getBytes());
    } else {
    byte[] bytes = zkClient.getData().forPath(path);
    Long seq = Long.valueOf(new String(bytes));
    zkClient.setData().forPath(path, (seq + step + "").getBytes());
    }

    因为需要实时修改zookeeper的节点信息,可以考虑建立序列池,例如直接取走10000个序列,由各个服务内部自己去生成,具体实现主要依赖到CAS,通过compareAndSet去实现单机内部的序号递增,避免锁的滥用

  • 相关阅读:
    使用Jquery的Ajax调用后台方法
    FileUpload与UpdatePanel
    OnClick与OnClientClick的时序和条件
    LinQ使用积累
    If...Else转换为Action的写法
    淘宝对接(二)
    淘宝对接(一)
    dialog传值
    android sdk开发包国内下载地址合集
    admob android
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12014177.html
Copyright © 2011-2022 走看看