zoukankan      html  css  js  c++  java
  • 分布式服务自增长唯一ID小结

    1、常用生成唯一ID的方式,例如UUID

    2、生成唯一自自增长ID方式:

      例如:

      • Zookeeper的增加ID;
      • redis的incr方法
      • mongodb的objectId

    3、采用雪花模型

    如下代码:

      1 /**
      2  * 采用twitter的雪花算法,生成有一定顺序且不重复的id,结果类型为64位的long型
      3  */
      4 public class SnowflakeIdUtils {
      5     //集群id
      6     private long datacenterId;
      7     //机器id
      8     private long workerId;
      9     //序列号
     10     private long sequenceId;
     11 
     12     //集群id的bit位数
     13     private long datacenterIdBits = 5L;
     14     //机器id的bit位数
     15     private long workerIdBits = 5L;
     16     //序列号的bit位数
     17     private long sequenceIdBits = 12L;
     18 
     19     //集群id的最大编号
     20     private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
     21     //机器id的最大编号
     22     private long maxWorkerId = -1L ^ (-1L << workerIdBits);
     23     //序列号的掩码
     24     private long sequenceIdMask = -1L ^ (-1L << sequenceIdBits);
     25 
     26     //生成最终结果时,集群id需移动的bit位数
     27     private long timestampShiftBits = sequenceIdBits + workerIdBits + datacenterIdBits;
     28     //生成最终结果时,集群id需移动的bit位数
     29     private long datacenterIdShiftBits = sequenceIdBits + workerIdBits;
     30     //生成最终结果时,机器id需移动的bit位数
     31     private long workerIdShiftBits = sequenceIdBits;
     32 
     33     //去掉过去的时间,即从指定时间(本例以2017-10-12 00:00:00)开始算,
     34     // 大约可用69.5年(41位的时间位,最大值换成毫秒,再换算成年,大约69.5年)
     35     //1507737600000为从1970-01-01 00:00:00到2017-10-12 00:00:00经过的毫秒数
     36     private long pastMills = 1507737600000L;
     37     //上一次生成id使用的timestamp ,以毫秒为单位
     38     private long lastTimestamp = 1L;
     39 
     40     /**
     41      * 若没有指定集群id和机器id,则默认均为0
     42      */
     43     public SnowflakeIdUtils() {
     44         this(0, 0);
     45     }
     46 
     47     /**
     48      * 指定集群id和机器id
     49      *
     50      * @param datacenterId
     51      * @param workerId
     52      */
     53     public SnowflakeIdUtils(long datacenterId, long workerId) {
     54         if (datacenterId < 0 || datacenterId > maxDatacenterId) {
     55             throw new RuntimeException(String.format("datacenterId greater than %d or less than 0", maxDatacenterId));
     56         }
     57         if (workerId < 0 || workerId > maxWorkerId) {
     58             throw new RuntimeException(String.format("workerId greater than %d or less than 0", maxWorkerId));
     59         }
     60         this.datacenterId = datacenterId;
     61         this.workerId = workerId;
     62     }
     63 
     64     /**
     65      * 生成全局唯一的id
     66      *
     67      * @return
     68      */
     69     public synchronized long nextId() {
     70         long timestamp = System.currentTimeMillis();
     71         if (timestamp < lastTimestamp) {  //出现这种情况,通常是由于机器时间出问题了
     72             throw new RuntimeException("machine time error");
     73         }
     74 
     75         //同一时刻生成的id号
     76         if (timestamp == lastTimestamp) {
     77             sequenceId = (sequenceId + 1) & sequenceIdMask;
     78             if (sequenceId == 0) {  //说明当前毫秒的序列号用完了,需从下个毫秒数开始重新计数
     79                 timestamp = nextTimestamp(lastTimestamp);
     80             }
     81         } else {
     82             //否则序列号从0开始
     83             sequenceId = 0L;
     84         }
     85 
     86         lastTimestamp = timestamp;
     87         long id = ((timestamp - pastMills) << timestampShiftBits)
     88                 | (datacenterId << datacenterIdShiftBits)
     89                 | (workerId << workerIdShiftBits)
     90                 | sequenceId;
     91         return id;
     92     }
     93 
     94     /**
     95      * 获取上次取数毫秒的下一时刻
     96      *
     97      * @param lastTimestamp
     98      * @return
     99      */
    100     long nextTimestamp(long lastTimestamp) {
    101         long timestamp = System.currentTimeMillis();
    102         while (timestamp <= lastTimestamp) {
    103             timestamp = System.currentTimeMillis();
    104         }
    105         return timestamp;
    106     }
    107 
    108     public static void main(String[] args) throws Exception {
    109         SnowflakeIdUtils snowflakeIdGen = new SnowflakeIdUtils();
    110         //测试,生成10个唯一id
    111         for (int i = 0; i < 10; i++) {
    112             long id = snowflakeIdGen.nextId();
    113             System.out.println(id);
    114         }
    115     }
    116 }

    这里采用的是默认构造生成 SnowflakeIdUtils,如果分布式服务同时调用的话,会出现重复ID,

    所以需要加上 集群id(0~31),workerId(0~31)

    了解更多雪花模型知识,后续补充。

  • 相关阅读:
    波段是金牢记六大诀窍
    zk kafka mariadb scala flink integration
    Oracle 体系结构详解
    图解 Database Buffer Cache 内部原理(二)
    SQL Server 字符集介绍及修改方法演示
    SQL Server 2012 备份与还原详解
    SQL Server 2012 查询数据库中所有表的名称和行数
    SQL Server 2012 查询数据库中表格主键信息
    SQL Server 2012 查询数据库中所有表的索引信息
    图解 Database Buffer Cache 内部原理(一)
  • 原文地址:https://www.cnblogs.com/atomicbomb/p/9648228.html
Copyright © 2011-2022 走看看