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

发布于:2025-04-16 ⋅ 阅读:(19) ⋅ 点赞:(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

分布式系统

时间戳

实现简单,性能高

可能重复

对唯一性要求不高

 

 


网站公告

今日签到

点亮在社区的每一天
去签到