全局唯一标识符(UID)生成策略

发布于:2025-04-16 ⋅ 阅读:(92) ⋅ 点赞:(0)

目录

一、UUID

二、雪花算法

三、时间戳 + 随机数

四、利用数据库的自增字段

五、 基于 Redis 的原子操作

总结


 

在信息系统中,生成唯一ID是非常常见的需求,尤其是在分布式系统或高并发场景下。以下是几种常见的生成唯一ID的算法或方式:

 

一、UUID

UUID(通用唯一识别码,Universally Unique Identifier)是一种用于标识信息的标准化方法,确保在全球范围内的唯一性。UUID通常以32个十六进制数字表示,分为五组,形式为 8-4-4-4-12,例如:123e4567-e89b-12d3-a456-426614174000。

C#示例:

using System;

class UUIDExample
{
    static void Main()
    {
        // 生成一个随机UUID (Version 4)
        Guid uuid = Guid.NewGuid();
        Console.WriteLine(uuid); // 输出示例: 123e4567-e89b-12d3-a456-426614174000
    }
}

特点:

  • 长度固定为128位(通常以36字符的字符串形式表示)。
  • 唯一性依赖于标准算法,冲突概率极低。
  • 不适合需要排序或较短ID的场景。

 

二、雪花算法

雪花算法(Snowflake Algorithm)是 Twitter 在 2010 年开源的一种分布式 ID 生成算法,用于在分布式系统中生成全局唯一的 ID。它的核心思想是将一个 64 位的 ID 分成多个部分,每个部分代表不同的信息,例如时间戳、机器 ID 和序列号等。

雪花算法的 ID 结构

雪花算法生成的 64 位 ID 结构如下:

| 1 bit | 41 bits | 10 bits | 12 bits |

|-------|---------|---------|---------|

| sign  |  timestamp | machine ID | sequence |

  • 1 bit:符号位,固定为 0,表示正数。
  • 41 bits:时间戳(毫秒级),表示从某个起始时间到当前时间的毫秒数。可以使用约 69 年。
  • 10 bits:机器 ID,表示生成 ID 的机器或节点。最多支持 1024 个节点。
  • 12 bits:序列号,表示同一毫秒内生成的 ID 序列号。每毫秒最多生成 4096 个 ID。

C# 实现雪花算法

以下是一个简单的 C# 实现:

using System;

public class SnowflakeIdGenerator
{
    // 起始时间戳(2023-01-01 00:00:00)
    private readonly DateTime _epoch = new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    // 机器 ID 所占的位数
    private const int MachineIdBits = 10;

    // 序列号所占的位数
    private const int SequenceBits = 12;

    // 最大机器 ID
    private const long MaxMachineId = ~(-1L << MachineIdBits);

    // 最大序列号
    private const long MaxSequence = ~(-1L << SequenceBits);

    // 机器 ID 向左移的位数
    private const int MachineIdShift = SequenceBits;

    // 时间戳向左移的位数
    private const int TimestampShift = SequenceBits + MachineIdBits;

    private readonly long _machineId;
    private long _lastTimestamp = -1L;
    private long _sequence = 0L;

    public SnowflakeIdGenerator(long machineId)
    {
        if (machineId < 0 || machineId > MaxMachineId)
        {
            throw new ArgumentOutOfRangeException(nameof(machineId), "Machine ID must be between 0 and " + MaxMachineId);
        }

        _machineId = machineId;
    }

    public long NextId()
    {
        long currentTimestamp = GetCurrentTimestamp();

        if (currentTimestamp == _lastTimestamp)
        {
            _sequence = (_sequence + 1) & MaxSequence;
            if (_sequence == 0)
            {
                // 同一毫秒内序列号用尽,等待下一毫秒
                currentTimestamp = WaitForNextMillisecond(_lastTimestamp);
            }
        }
        else
        {
            _sequence = 0;
        }

        _lastTimestamp = currentTimestamp;

        return ((currentTimestamp - _epoch.Ticks) << TimestampShift) |
               (_machineId << MachineIdShift) |
               _sequence;
    }

    private long GetCurrentTimestamp()
    {
        return new DateTime(DateTime.UtcNow.Ticks, DateTimeKind.Utc).Ticks - _epoch.Ticks;
    }

    private long WaitForNextMillisecond(long lastTimestamp)
    {
        long timestamp = GetCurrentTimestamp();
        while (timestamp <= lastTimestamp)
        {
            timestamp = GetCurrentTimestamp();
        }
        return timestamp;
    }
}

class Program
{
    static void Main(string[] args)
    {
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1); // 机器 ID 为 1

        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(idGenerator.NextId());
        }
    }
}

特点:

  • 每个ID是64位整数,结构清晰。
  • 支持分布式系统,不同机器通过配置不同的workerId和datacenterId避免冲突。
  • 支持排序,适合需要按时间排序的场景。

 

三、时间戳 + 随机数

通过结合当前时间戳和随机数来生成唯一 ID,不过这种方法在高并发场景下可能会有重复的风险。

using System;

class Program
{
    static void Main()
    {
        long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
        Random random = new Random();
        int randomNumber = random.Next(1000, 9999);
        string uniqueId = $"{timestamp}{randomNumber}";
        Console.WriteLine(uniqueId);
    }
}

特点:

  • 实现简单,性能高。
  • 可能存在重复问题(需要结合其他信息如机器ID)。

 

利用数据库的自增字段

利用数据库的自增字段(如 MySQL 的 AUTO_INCREMENT 或 SQL Server 的 IDENTITY)生成唯一ID。

C# 示例:

using System;
using System.Data.SqlClient;

class Program
{
    static void Main()
    {
        string connectionString = "Server=your_server;Database=your_db;User Id=your_user;Password=your_password;";
        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            connection.Open();
            string query = "INSERT INTO YourTable (Name) VALUES ('SampleName'); SELECT SCOPE_IDENTITY();";
            using (SqlCommand command = new SqlCommand(query, connection))
            {
                object result = command.ExecuteScalar();
                long uniqueId = Convert.ToInt64(result);
                Console.WriteLine($"Generated Database ID: {uniqueId}");
            }
        }
    }
}

特点:

  • 简单易用,适合单机或小规模系统。
  • 不适合分布式系统,因为需要集中管理自增ID。

 

五、 基于 Redis 的原子操作

Redis 提供了原子递增操作(INCR),可以用来生成唯一ID。

C# 示例:

using System;
using StackExchange.Redis;

class Program
{
    static void Main()
    {
        ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
        IDatabase db = redis.GetDatabase();

        long uniqueId = db.StringIncrement("UniqueIdCounter");
        Console.WriteLine($"Generated Redis ID: {uniqueId}");
    }
}

特点:

  • 高效且支持分布式系统。
  • 需要维护一个独立的 Redis 实例。

 

总结

方法

优点

缺点

使用场景

UUID

标准化,冲突概率极低

较长,不易排序

分布式系统,无需排序

Snowflake

高效,支持分布式,可排序

需要配置机器ID和数据中心ID

分布式系统,需排序

数据库自增主键

简单易用

不适合分布式

单机或小规模系统

Redis 原子操作

高效,支持分布式

需要维护 Redis

分布式系统

时间戳

实现简单,性能高

可能重复

对唯一性要求不高