一个简单的用C#实现的分布式雪花ID算法

雪花ID是一个依赖时间戳根据算法生成的一个Int64的数字ID,一般用来做主键或者订单号等。以下是一个用C#写的雪花ID的简单实现方法

csharp 复制代码
using System;
using System.Collections.Concurrent;
using System.Diagnostics;

public class SnowflakeIdGenerator
{
    // 配置常量
    private const int SignBits = 1;// 符号位
    private const int TimestampBits = 41;// 时间戳位,最大值2^41-1=2,147,483,647ms,69年
    private const int DataCenterIdBits = 4;// 数据中心ID位,最大值2^4-1=15
    private const int MachineIdBits = 6;// 机器ID位,最大值2^6-1=63
    private const int DefaultSequenceBits = 12;// 自增序号位,最大值2^12-1=4095
    private const int ProcessIdBits = 4;// 进程ID位,最大值2^4-1=15
    private const int SequenceBitsWithProcess = 8;//如果使用进程ID,则为8位,否则为12位,最大值2^8-1=255

    // 位移计算常量
    private const int TimestampShift = 64 - SignBits - TimestampBits;
    private const int DataCenterShift = TimestampShift - DataCenterIdBits;
    private const int MachineShift = DataCenterShift - MachineIdBits;
    private const int ProcessShift = SequenceBitsWithProcess;

    // 基准时间
    private static readonly DateTime Epoch = new(2025, 3, 1, 0, 0, 0, DateTimeKind.Utc);
    private const long MaxTimestamp = (1L << TimestampBits) - 1;

    // 单例存储
    private static readonly ConcurrentDictionary<string, SnowflakeIdGenerator> _instances = new();

    // 各ID最大值
    private readonly long _maxDataCenterId = (1 << DataCenterIdBits) - 1;
    private readonly long _maxMachineId = (1 << MachineIdBits) - 1;
    private readonly long _maxProcessId = (1 << ProcessIdBits) - 1;
    private readonly long _maxSequence;

    // 状态控制
    private readonly object _lock = new object();
    private long _lastTimestamp = -1L;
    private int _sequence = 0;

    // 节点信息
    public int DataCenterId { get; }// 数据中心ID
    public int MachineId { get; }// 机器ID
    public int ProcessId { get; }// 进程ID
    public bool UseProcessId { get; }// 是否使用进程ID

    private SnowflakeIdGenerator(int dataCenterId, int machineId, int processId)
    {
        // 参数校验逻辑
        ValidateId(dataCenterId, (1 << DataCenterIdBits) - 1, nameof(dataCenterId));
        ValidateId(machineId, (1 << MachineIdBits) - 1, nameof(machineId));

        UseProcessId = processId != 0;
        if (UseProcessId)
        {
            ValidateId(processId, (1 << ProcessIdBits) - 1, nameof(processId));
        }

        DataCenterId = dataCenterId;
        MachineId = machineId;
        ProcessId = processId;
    }

    public static SnowflakeIdGenerator GetInstance(int dataCenterId, int machineId, int processId = 0)
    {
        var key = $"{dataCenterId}-{machineId}-{processId}";
        return _instances.GetOrAdd(key, _ => new SnowflakeIdGenerator(dataCenterId, machineId, processId));
    }
    /// <summary>
    /// 产生下一个ID
    /// </summary>
    /// <returns></returns>
    public long NextId()
    {
        lock (_lock)
        {
            var timestamp = GetValidTimestamp();

            if (timestamp == _lastTimestamp)
            {
                _sequence++;
                if (_sequence > MaxSequence)
                {
                    timestamp = WaitNextMillis(timestamp);
                    _sequence = 0;
                }
            }
            else
            {
                _sequence = 0;
            }

            _lastTimestamp = timestamp;

            return BuildId(timestamp);
        }
    }
    /// <summary>
    /// 获取最大序号
    /// </summary>
    private int MaxSequence => UseProcessId ?
       (1 << SequenceBitsWithProcess) - 1 :
       (1 << DefaultSequenceBits) - 1;
    /// <summary>
    /// 拼接生成ID
    /// </summary>
    /// <param name="timestamp"></param>
    /// <returns></returns>
    private long BuildId(long timestamp)
    {
        var id = (timestamp << TimestampShift)
               | ((long)DataCenterId << DataCenterShift)
               | ((long)MachineId << MachineShift);

        if (UseProcessId)
        {
            return id | ((long)ProcessId << ProcessShift) | (uint)_sequence;
        }
        return id | (uint)_sequence;
    }
    /// <summary>
    /// 获取有效的时间戳,防止时间回拨或系统时钟溢出
    /// </summary>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException"></exception>
    private long GetValidTimestamp()
    {
        var timestamp = (DateTimeOffset.UtcNow.Ticks - Epoch.Ticks) / TimeSpan.TicksPerMillisecond;

        if (timestamp < _lastTimestamp)
        {
            throw new InvalidOperationException(
                $"Clock moved backwards. Refusing to generate ID for {_lastTimestamp - timestamp}ms");
        }

        if (timestamp > MaxTimestamp)
        {
            throw new InvalidOperationException(
                $"System clock overflow. Timestamp exceeds {TimestampBits} bits.");
        }

        return timestamp;
    }
    // 等待下一毫秒,产生新的时间戳
    private static long WaitNextMillis(long currentTimestamp)
    {
        long timestamp;
        var spinWait = new SpinWait();
        do
        {
            spinWait.SpinOnce();
            timestamp = (DateTimeOffset.UtcNow.Ticks - Epoch.Ticks) / TimeSpan.TicksPerMillisecond;
        } while (timestamp <= currentTimestamp);

        return timestamp;
    }

    // 校验ID,必须在0到最大值之间
    private static void ValidateId(int value, long maxValue, string paramName)
    {
        if (value < 0 || value > maxValue)
        {
            throw new ArgumentOutOfRangeException(paramName,
                $"Value must be between 0 and {maxValue}");
        }
    }
}

调用方式

csharp 复制代码
 //获取单例实例
 var generator = SnowflakeIdGenerator.GetInstance(dataCenterId: 1, machineId: 5);//推荐
 long id = generator.NextId();
 //或者,加入进程ID
 var generator = SnowflakeIdGenerator.GetInstance(dataCenterId: 1, machineId: 5, processId: 10);
 long id = generator.NextId();
相关推荐
leiming66 分钟前
c++ string 容器
开发语言·c++·算法
缺点内向28 分钟前
如何在 C# 中将 Word 文档转换为 EMF(增强型图元文件)
开发语言·c#·word·.net
wljun7391 小时前
六、OrcaSlicer 切片之区域
算法·切片软件 orcaslicer
2401_841495641 小时前
【LeetCode刷题】跳跃游戏Ⅱ
数据结构·python·算法·leetcode·数组·贪心策略·跳跃游戏
leaves falling1 小时前
动态规划讲解
算法·动态规划
MyBFuture1 小时前
C# 哈希表与堆栈队列实战指南
开发语言·windows·c#·visual studio
钓鱼的肝1 小时前
GESP系列(3级)小杨的储蓄
开发语言·数据结构·c++·笔记·算法·gesp
MicroTech20251 小时前
MLGO微算法科技推出人工智能与量子计算融合新成果:基于QLSS与LCHS的量子DPM算法技术
人工智能·科技·算法
AndrewHZ1 小时前
【图像处理基石】[特殊字符]圣诞特辑:10+经典图像处理算法,让你的图片充满节日氛围感!
图像处理·人工智能·opencv·算法·计算机视觉·stable diffusion·节日氛围感
艾醒2 小时前
大模型原理剖析——矩阵吸收优化:LLM推理加速的核心原理与实践
算法