关于分布式环境下的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 }
原文地址:https://www.cnblogs.com/sachem/p/9244494.html