阅读量:0
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。