基於.NET Standard的分布式自增ID算法--Snowflake代碼實現


概述

上篇文章介紹了3種常見的Id生成算法,本篇主要介紹如何使用C#實現Snowflake。

基礎字段

/// <summary>
/// 工作節點Id(長度為5位)
/// </summary>
public long WorkId{get;protected set;}

/// <summary>
/// 機房Id(長度為5位)
/// </summary>
public long DataCenterId{get;protected set;}

/// <summary>
/// 當前生成的Id
/// </summary>
public long CurrentId { get;protected set; }

基礎方法

//獲取當前時間的Unix時間戳
 private long TimeGen()
{
      return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}

//生成新時間戳(一定比上次生成的時間戳大)
 private long TilNextMillis(long lastTimestamp)
 {
      var timestamp = TimeGen();
      while (timestamp <= lastTimestamp)
      {
           timestamp = TimeGen();
      }
       return timestamp;
}

Id生成核心方法

        private const long TwEpoch = 1543765593681L;//2018-12-2 15:47:06 +00:00

        private const int WorkerIdBits = 5;
        private const int DatacenterIdBits = 5;
        private const int SequenceBits = 12;
        private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits);
        private const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits);

        private const int WorkerIdShift = SequenceBits;
        private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
        private const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;
        private const long SequenceMask = -1L ^ (-1L << SequenceBits);

        private long _sequence = 0L;
        private long _lastTimestamp = -1L;

        private readonly object _lock = new object();
        
         public long NextId()
        {
            lock (_lock)
            {
                var timestamp = TimeGen();
                if (timestamp < _lastTimestamp)
                {
                    //TODO 是否可以考慮直接等待?
                    throw new Exception(
                        $"Clock moved backwards or wrapped around. Refusing to generate id for {_lastTimestamp - timestamp} ticks");
                }

                if (_lastTimestamp == timestamp)
                {
                    _sequence = (_sequence + 1) & SequenceMask;
                    if (_sequence == 0)
                    {
                        timestamp = TilNextMillis(_lastTimestamp);
                    }
                }
                else
                {
                    _sequence = 0;
                }
                _lastTimestamp = timestamp;
                CurrentId = ((timestamp - TwEpoch) << TimestampLeftShift) |
                         (DatacenterId << DatacenterIdShift) |
                         (WorkerId << WorkerIdShift) | _sequence;

                return CurrentId;
            }
        }

完整實現、使用Demo以及benchmark測試請參見源代碼:https://github.com/sampsonye/nice



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM