Snowflake 是 Twitter 開(kāi)源的分布式 ID 生成算法,它可以在不依賴(lài)數(shù)據(jù)庫(kù)的情況下生成全局唯一的 ID。下面是一個(gè)簡(jiǎn)單的 C# 實(shí)現(xiàn):
using System;
public class Snowflake
{
// 基準(zhǔn)時(shí)間
private static readonly DateTime Epoch = new DateTime(2021, 1, 1, 0, 0, 0, DateTimeKind.Utc);
// 機(jī)器 ID 所占位數(shù)
private const int WorkerIdBits = 5;
// 數(shù)據(jù)中心 ID 所占位數(shù)
private const int DatacenterIdBits = 5;
// 序列號(hào)所占位數(shù)
private const int SequenceBits = 12;
// 機(jī)器 ID 左移位數(shù)
private const int WorkerIdShift = SequenceBits;
// 數(shù)據(jù)中心 ID 左移位數(shù)
private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
// 時(shí)間戳左移位數(shù)
private const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;
// 最大序列號(hào)
private const long MaxSequence = (1L << SequenceBits) - 1;
// 機(jī)器 ID 和數(shù)據(jù)中心 ID 的最大值
private const long MaxWorkerId = (1L<< WorkerIdBits) - 1;
private const long MaxDatacenterId = (1L<< DatacenterIdBits) - 1;
// 機(jī)器 ID
private readonly long _workerId;
// 數(shù)據(jù)中心 ID
private readonly long _datacenterId;
// 序列號(hào)
private long _sequence;
// 上次生成 ID 的時(shí)間戳
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);
這個(gè)實(shí)現(xiàn)中,我們使用了一個(gè)基準(zhǔn)時(shí)間(Epoch),機(jī)器 ID(workerId),數(shù)據(jù)中心 ID(datacenterId)和序列號(hào)(sequence)來(lái)生成全局唯一的 ID。你需要為每個(gè)工作節(jié)點(diǎn)分配一個(gè)唯一的機(jī)器 ID 和數(shù)據(jù)中心 ID。