Snowflake 是 Twitter 開源的分布式 ID 生成算法,它可以在不依賴數據庫的情況下生成全局唯一的 ID。下面是一個簡單的 C# 實現:
using System;
public class Snowflake
{
// 基準時間
private static readonly DateTime Epoch = new DateTime(2021, 1, 1, 0, 0, 0, DateTimeKind.Utc);
// 機器 ID 所占位數
private const int WorkerIdBits = 5;
// 數據中心 ID 所占位數
private const int DatacenterIdBits = 5;
// 序列號所占位數
private const int SequenceBits = 12;
// 機器 ID 左移位數
private const int WorkerIdShift = SequenceBits;
// 數據中心 ID 左移位數
private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
// 時間戳左移位數
private const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;
// 最大序列號
private const long MaxSequence = (1L << SequenceBits) - 1;
// 機器 ID 和數據中心 ID 的最大值
private const long MaxWorkerId = (1L<< WorkerIdBits) - 1;
private const long MaxDatacenterId = (1L<< DatacenterIdBits) - 1;
// 機器 ID
private readonly long _workerId;
// 數據中心 ID
private readonly long _datacenterId;
// 序列號
private long _sequence;
// 上次生成 ID 的時間戳
private long _lastTimestamp;
public Snowflake(long workerId, long datacenterId, long sequence = 0L)
{
if (workerId < 0 || workerId > MaxWorkerId)
throw new ArgumentException($"Worker Id must be between 0 and {MaxWorkerId}");
if (datacenterId < 0 || datacenterId > MaxDatacenterId)
throw new ArgumentException($"Datacenter Id must be between 0 and {MaxDatacenterId}");
_workerId = workerId;
_datacenterId = datacenterId;
_sequence = sequence;
}
public long NextId()
{
lock (this)
{
var timestamp = GetCurrentTimestamp();
if (timestamp < _lastTimestamp)
throw new Exception("Invalid system clock");
if (_lastTimestamp == timestamp)
{
_sequence = (_sequence + 1) & MaxSequence;
if (_sequence == 0)
timestamp = WaitNextMillisecond(_lastTimestamp);
}
else
{
_sequence = 0;
}
_lastTimestamp = timestamp;
return ((timestamp - Epoch.Ticks)<< TimestampLeftShift) |
(_datacenterId<< DatacenterIdShift) |
(_workerId<< WorkerIdShift) |
_sequence;
}
}
private long GetCurrentTimestamp()
{
return (DateTime.UtcNow - Epoch).Ticks / 10000;
}
private long WaitNextMillisecond(long lastTimestamp)
{
var timestamp = GetCurrentTimestamp();
while (timestamp <= lastTimestamp)
timestamp = GetCurrentTimestamp();
return timestamp;
}
}
使用方法:
var snowflake = new Snowflake(1, 1);
var id = snowflake.NextId();
Console.WriteLine(id);
這個實現中,我們使用了一個基準時間(Epoch),機器 ID(workerId),數據中心 ID(datacenterId)和序列號(sequence)來生成全局唯一的 ID。你需要為每個工作節點分配一個唯一的機器 ID 和數據中心 ID。