• 分布式服务自增长唯一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)

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

  • 相关阅读:
    2016/11/17 周四 <javascript的封装简单示例>
    JavaScript资源大全中文版(Awesome最新版转载自张果老师博客)
    <web Font的使用>
    博客园首页飘彩色雪花代码
    C#多线程
    SQL Server数据库优化措施:索引优化(转)
    HOWTO: InstallShield中如何实现MSI包的权限提升(转)
    C# 获取操作系统版本信息
    installshield msi程序安装问题
    bat和VBS
  • 原文地址:https://www.cnblogs.com/atomicbomb/p/9648228.html
Copyright © 2020-2023  润新知