C#如何实现雪花算法 Snowflake ID生成器

来源:开发教程作者:Ada头衔:草根站长
导读:本期聚焦于小伙伴创作的《C#如何实现雪花算法 Snowflake ID生成器》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何实现雪花算法 Snowflake ID生成器》有用,将其分享出去将是对创作者最好的鼓励。

雪花算法是Twitter开源的分布式ID生成算法,核心思想是将一个64位的ID拆分为不同部分,分别存储时间戳、机器标识和序列号,以此保证在分布式环境下生成的ID全局唯一且趋势递增。在C#中实现该算法,需要先明确ID的位划分规则,再结合线程安全、时钟回拨等场景做适配处理。

C#如何实现雪花算法 Snowflake ID生成器

雪花算法ID结构说明

标准的雪花算法64位ID划分如下:

  • 最高位(1位):固定为0,保证ID为正数
  • 时间戳部分(41位):记录当前时间与自定义起始时间的差值,单位通常为毫秒,可支持约69年的时间范围
  • 机器ID部分(10位):分为5位数据中心ID和5位机器ID,最多支持1024个节点
  • 序列号部分(12位):同一毫秒内自增的序列,最多支持每毫秒生成4096个ID

C#实现核心逻辑

实现时需要注意几个关键点:一是使用lock关键字保证多线程下的序列号自增和ID生成的线程安全;二是处理时钟回拨场景,避免生成重复ID;三是合理设置起始时间戳,减少时间戳差值溢出的风险。

完整实现代码

using System;

public class SnowflakeIdGenerator
{
    // 起始时间戳(可自定义,建议设置为项目上线时间的时间戳毫秒值)
    private static readonly long START_TIMESTAMP = 1609459200000L; // 2021-01-01 00:00:00的毫秒时间戳

    // 各部分占用的位数
    private static readonly int SEQUENCE_BITS = 12; // 序列号位数
    private static readonly int MACHINE_ID_BITS = 5; // 机器ID位数
    private static readonly int DATA_CENTER_ID_BITS = 5; // 数据中心ID位数

    // 最大取值计算
    private static readonly long MAX_MACHINE_ID = -1L ^ (-1L << MACHINE_ID_BITS);
    private static readonly long MAX_DATA_CENTER_ID = -1L ^ (-1L << DATA_CENTER_ID_BITS);
    private static readonly long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BITS);

    // 各部分左移位数
    private static readonly int MACHINE_ID_SHIFT = SEQUENCE_BITS;
    private static readonly int DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS;
    private static readonly int TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS + DATA_CENTER_ID_BITS;

    // 实例变量
    private readonly long _dataCenterId;
    private readonly long _machineId;
    private long _sequence = 0L; // 当前毫秒内的序列号
    private long _lastTimestamp = -1L; // 上一次生成ID的时间戳

    private readonly object _lockObj = new object();

    /// <summary>
    /// 初始化雪花ID生成器
    /// </summary>
    /// <param name="dataCenterId">数据中心ID,范围0~31</param>
    /// <param name="machineId">机器ID,范围0~31</param>
    public SnowflakeIdGenerator(long dataCenterId, long machineId)
    {
        if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0)
        {
            throw new ArgumentException($"数据中心ID必须在0到{MAX_DATA_CENTER_ID}之间");
        }
        if (machineId > MAX_MACHINE_ID || machineId < 0)
        {
            throw new ArgumentException($"机器ID必须在0到{MAX_MACHINE_ID}之间");
        }
        _dataCenterId = dataCenterId;
        _machineId = machineId;
    }

    /// <summary>
    /// 生成下一个唯一ID
    /// </summary>
    public long NextId()
    {
        lock (_lockObj)
        {
            long currentTimestamp = GetCurrentTimestamp();
            // 处理时钟回拨
            if (currentTimestamp < _lastTimestamp)
            {
                throw new InvalidOperationException($"时钟回拨,拒绝生成ID,回拨时间差:{_lastTimestamp - currentTimestamp}毫秒");
            }

            // 同一毫秒内
            if (currentTimestamp == _lastTimestamp)
            {
                _sequence = (_sequence + 1) & MAX_SEQUENCE;
                // 序列号溢出,等待下一毫秒
                if (_sequence == 0)
                {
                    currentTimestamp = WaitNextMillis(_lastTimestamp);
                }
            }
            else
            {
                // 不同毫秒内,序列号重置为0
                _sequence = 0;
            }

            _lastTimestamp = currentTimestamp;

            // 组装ID
            return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
                   | (_dataCenterId << DATA_CENTER_ID_SHIFT)
                   | (_machineId << MACHINE_ID_SHIFT)
                   | _sequence;
        }
    }

    /// <summary>
    /// 获取当前时间戳(毫秒)
    /// </summary>
    private long GetCurrentTimestamp()
    {
        return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
    }

    /// <summary>
    /// 等待直到下一毫秒
    /// </summary>
    private long WaitNextMillis(long lastTimestamp)
    {
        long timestamp = GetCurrentTimestamp();
        while (timestamp <= lastTimestamp)
        {
            timestamp = GetCurrentTimestamp();
        }
        return timestamp;
    }
}

使用示例

在业务代码中可以直接实例化生成器并调用方法获取ID:

class Program
{
    static void Main(string[] args)
    {
        // 初始化生成器,数据中心ID为1,机器ID为1
        SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);
        // 生成10个ID并打印
        for (int i = 0; i < 10; i++)
        {
            long id = generator.NextId();
            Console.WriteLine($"生成的Snowflake ID:{id}");
        }
    }
}

注意事项

  • 起始时间戳建议设置为项目正式上线的时间,避免时间戳差值过早达到上限
  • 如果部署环境存在时钟回拨问题,可以扩展代码逻辑,比如记录回拨时间并等待恢复,或者临时切换备用生成策略
  • 机器ID和数据中心ID需要保证在分布式集群中唯一,可以通过配置文件、环境变量或者注册中心分配
  • 该实现是单实例的,如果需要在多实例场景下使用,只需要保证不同实例的机器ID和数据中心ID不重复即可

C#Snowflake_IDID生成器分布式ID修改时间:2026-07-06 18:45:26

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。