• 关于分布式环境下的id生成


      1 public class IdWorker
      2     {
      3         //基准时间
      4         public const long Twepoch = 1288834974657L;
      5 
      6         //机器标识位数
      7         private const int WorkerIdBits = 6;
      8 
      9         //数据标志位数
     10         private const int DatacenterIdBits = 6;
     11 
     12         //序列号识位数
     13         private const int SequenceBits = 10;
     14 
     15         //机器ID最大值
     16         private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits);
     17 
     18         //数据标志ID最大值
     19         private const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits);
     20 
     21         //序列号ID最大值
     22         private const long SequenceMask = -1L ^ (-1L << SequenceBits);
     23 
     24         //机器ID偏左移10位
     25         private const int WorkerIdShift = SequenceBits;
     26 
     27         //数据ID偏左移15位
     28         private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
     29 
     30         //时间毫秒左移20位
     31         public const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;
     32 
     33         private static readonly DateTime Jan1St1970 = new DateTime
     34             (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
     35 
     36         private readonly object _lock = new object();
     37         private long _lastTimestamp = -1L;
     38 
     39         public IdWorker(long workerId, long datacenterId, long sequence = 0L)
     40         {
     41             // 如果超出范围就抛出异常
     42             if (workerId > MaxWorkerId || workerId < 0)
     43                 throw new ArgumentException(string.Format("worker Id 必须大于0,且不能大于MaxWorkerId: {0}", MaxWorkerId));
     44 
     45             if (datacenterId > MaxDatacenterId || datacenterId < 0)
     46                 throw new ArgumentException(string.Format("datacenterId Id 必须大于0,且不能大于MaxWorkerId: {0}",
     47                     MaxDatacenterId));
     48 
     49             //先检验再赋值
     50             WorkerId = workerId;
     51             DatacenterId = datacenterId;
     52             Sequence = sequence;
     53         }
     54 
     55         public long WorkerId { get; protected set; }
     56         public long DatacenterId { get; protected set; }
     57 
     58         public long Sequence { get; internal set; }
     59 
     60         public virtual long NextId(long dataNode=0)
     61         {
     62             lock (_lock)
     63             {
     64                 if (dataNode > MaxDatacenterId || dataNode < 0)
     65                     throw new ArgumentException($"dataNode 必须大于0,且不能大于MaxWorkerId: {MaxDatacenterId}");
     66                 if (dataNode == 0)
     67                     dataNode = DatacenterId;
     68                 var timestamp = TimeGen();
     69                 if (timestamp < _lastTimestamp)
     70                     throw new Exception($"时间戳必须大于上一次生成ID的时间戳.  拒绝为{_lastTimestamp - timestamp}毫秒生成id");
     71 
     72                 //如果上次生成时间和当前时间相同,在同一毫秒内
     73                 if (_lastTimestamp == timestamp)
     74                 {
     75                     //sequence自增,和sequenceMask相与一下,去掉高位
     76                     Sequence = (Sequence + 1) & SequenceMask;
     77                     //判断是否溢出,也就是每毫秒内超过1024,当为1024时,与sequenceMask相与,sequence就等于0
     78                     if (Sequence == 0)
     79                         timestamp = TilNextMillis(_lastTimestamp);
     80                 }
     81                 else
     82                 {
     83                     //如果和上次生成时间不同,重置sequence,就是下一毫秒开始,sequence计数重新从0开始累加,
     84                     //为了保证尾数随机性更大一些,最后一位可以设置一个随机数
     85                     Sequence = 0; //new Random().Next(10);
     86                 }
     87 
     88                 _lastTimestamp = timestamp;
     89                 return ((timestamp - Twepoch) << TimestampLeftShift) | (dataNode << DatacenterIdShift) |
     90                        (WorkerId << WorkerIdShift) | Sequence;
     91             }
     92         }
     93 
     94         /// <summary>
     95         /// 防止产生的时间比之前的时间还要小(由于NTP回拨等问题),保持增量的趋势.
     96         /// </summary>
     97         /// <param name="lastTimestamp"></param>
     98         /// <returns></returns>
     99         protected virtual long TilNextMillis(long lastTimestamp)
    100         {
    101             var timestamp = TimeGen();
    102             while (timestamp <= lastTimestamp)
    103                 timestamp = TimeGen();
    104             return timestamp;
    105         }
    106 
    107         /// <summary>
    108         /// 获取当前的时间戳
    109         /// </summary>
    110         /// <returns></returns>
    111         protected virtual long TimeGen()
    112         {
    113             return (long) (DateTime.UtcNow - Jan1St1970).TotalMilliseconds;
    114         }
    115     }
    1 public void GetId()
    2 {
    3   new IdWorker(1, 1).NextId();          
    4 }
  • 相关阅读:
    返回值与返回引用的问题
    C内存之指针传递
    Elasticsearch-Java中文搜索器(下)
    Elasticsearch-Java中文搜索器(中)
    Elasticsearch-Java中文搜索器(上)
    Redis和Memcache对比及选择
    Java + Tomcat + Memcached + Nginx 实现负载均衡~下
    Java + Tomcat + Memcached + Ecs 实现负载均衡~上
    Java -- 偏向锁、轻量级锁、自旋锁、重量级锁
    Java 锁与对象头
  • 原文地址:https://www.cnblogs.com/sachem/p/9244494.html
Copyright © 2020-2023  润新知