RuoVea.ExIdGen
10.0.0.3
dotnet add package RuoVea.ExIdGen --version 10.0.0.3
NuGet\Install-Package RuoVea.ExIdGen -Version 10.0.0.3
<PackageReference Include="RuoVea.ExIdGen" Version="10.0.0.3" />
<PackageVersion Include="RuoVea.ExIdGen" Version="10.0.0.3" />
<PackageReference Include="RuoVea.ExIdGen" />
paket add RuoVea.ExIdGen --version 10.0.0.3
#r "nuget: RuoVea.ExIdGen, 10.0.0.3"
#:package RuoVea.ExIdGen@10.0.0.3
#addin nuget:?package=RuoVea.ExIdGen&version=10.0.0.3
#tool nuget:?package=RuoVea.ExIdGen&version=10.0.0.3
🆔 RuoVea.ExIdGen
分布式唯一 ID 生成器 — 基于雪花漂移算法(移植自 yitter/idgenerator),生成 64 位长整型 ID、带前缀字符串 ID、以及基于时间戳的自增编号,内置中、英、法、日、繁体中文、粤语、越南语等 8 种语言的异常提示。
📖 目录
📋 概览
RuoVea.ExIdGen 为 .NET 开发者提供开箱即用的分布式唯一 ID 生成能力,基于雪花(Snowflake)算法并通过漂移补偿机制解决时钟回拨问题。
┌──────────────────────────────────────────────────────────┐
│ RuoVea.ExIdGen │
├──────────────────────────────────────────────────────────┤
│ ID 生成方式 │
│ ├─ Id (static long) → 64 位 Snowflake ID │
│ ├─ IdStr(prefix) → 带前缀字符串 ID │
│ ├─ No(format) → 时间戳自增长整型编号 │
│ └─ NoStr(format) → 时间戳自增字符串编号 │
│ │
│ 算法模式 │
│ ├─ Method 1 (默认) — 雪花漂移算法,时钟回拨补偿 │
│ ├─ Method 2 — 传统雪花算法,时钟回拨抛出异常 │
│ └─ Method 3 — 漂移算法 + DataCenter + 秒级时间戳 │
│ │
│ 配置方式 │
│ ├─ Configure(options) → IdGeneratorOptions 对象 │
│ ├─ Configure(workerId, seq) → 精简配置 │
│ └─ Configure(IConfiguration) → appsettings.json 驱动 │
├──────────────────────────────────────────────────────────┤
│ 国际化: zh-CN | zh-TW | zh-HK | en-US | fr-FR | │
│ ja-JP | vi-VN │
└──────────────────────────────────────────────────────────┘
设计原则
| 原则 | 说明 |
|---|---|
| 零配置启动 | 未调用 Configure 时自动初始化 WorkerId=0 的默认实例 |
| 漂移补偿 | Method 1 在单毫秒内序列号耗尽时自动"借用"下一毫秒,容忍短期时钟回拨 |
| 唯一性保证 | 由 WorkerId(机器码) + 时间戳 + 自增序列号三元组保证全局唯一 |
| 参数校验 | 初始化时对 WorkerId、SeqBitLength、BaseTime 等参数进行全面校验,抛出含本地化消息的异常 |
📦 安装
.NET CLI
# .NET 8.0
dotnet add package RuoVea.ExIdGen --version 8.0.1.1
# .NET 10.0
dotnet add package RuoVea.ExIdGen --version 10.0.0.2
Package Manager
Install-Package RuoVea.ExIdGen -Version 8.0.1.1
PackageReference
<PackageReference Include="RuoVea.ExIdGen" Version="8.0.1.1" />
支持的 Target Framework
| TFM | 最低版本 |
|---|---|
net8.0 |
8.0.1.1 |
net10.0 |
10.0.0.2 |
⚡ 30 秒快速开始
1. 导入命名空间
using RuoVea.ExIdGen; // IdGenerator, ConfigureOption
using RuoVea.ExIdGen.Contract; // IdGeneratorOptions, IIdGenerator
2. 配置并生成第一个 ID
// ① 配置(应用启动时执行一次)
IdGenerator.Configure(workerId: 1, seqBitLength: 6);
// ② 生成 64 位 Snowflake ID
long id = IdGenerator.Id;
Console.WriteLine(id); // 如: 745635281972854784
// ③ 生成带前缀的字符串 ID
string orderId = IdGenerator.IdStr("ORDER_");
Console.WriteLine(orderId); // "ORDER_745635281972854784"
3. 通过 appsettings.json 配置
{
"IdGenerator": {
"WorkerId": "1",
"SeqBitLength": "6"
}
}
// 在 Program.cs / Startup.cs 中
var configuration = builder.Configuration;
IdGenerator.Configure(configuration);
❗ 注意:
Configure(IConfiguration)方法存在 Bug——当配置文件中未提供SeqBitLength时,会将workerId错误赋值为 6(而非将seqBitLength赋值为 6)。请务必在配置文件中显式提供SeqBitLength字段,或改用Configure(ushort, byte)重载。
30 秒内你完成了: 导入命名空间 → 配置 WorkerId → 生成 Snowflake ID → 生成带前缀字符串 ID。
🧩 核心场景
场景一:生成 Snowflake ID(长整型)
┌──────────────┐ IdGenerator.Id ┌───────────────────┐
│ WorkerId=1 │ ─────────────────▶ │ 745635281972854784 │
│ (机器码) │ │ (64-bit long) │
└──────────────┘ └───────────────────┘
用例: 数据库主键、消息队列消息ID、全局唯一标识
// 生成单个 ID
long userId = IdGenerator.Id;
// 批量生成(用于数据迁移等场景)
var ids = new List<long>();
for (int i = 0; i < 1000; i++)
{
ids.Add(IdGenerator.Id);
}
// 验证唯一性
bool allUnique = ids.Distinct().Count() == ids.Count;
Console.WriteLine(allUnique); // True
场景二:生成带前缀的字符串 ID
┌──────────────┐ IdGenerator.IdStr("ORDER_") ┌──────────────────────────┐
│ WorkerId=1 │ ──────────────────────────▶ │ "ORDER_745635281972854784" │
└──────────────┘ └──────────────────────────┘
用例: 订单编号、物流单号、工单编号(人类可读前缀 + 机器唯一后缀)
// 无前缀
string id1 = IdGenerator.IdStr();
// → "745647812025876480"
// 业务前缀——订单
string orderId = IdGenerator.IdStr("ORD");
// → "ORD745647812025876480"
// 业务前缀——支付流水
string paymentId = IdGenerator.IdStr("PAY");
// → "PAY745647812025876481"
⚠️ 注意:
IdStr仅做字符串拼接(prefix + NextId()),不保证前缀在分布式场景下的唯一性。如需确保前缀 + 业务语义的全局唯一,应在业务层设计前缀规范。
场景三:生成基于时间的自增编号
┌──────────┐ IdGenerator.No("yyyyMMddHHmmss") ┌──────────────────────┐
│ 当前时间 │ ─────────────────────────────────▶ │ 202602231508451234 │
│ 随机后缀 │ │ (时间戳 + 4位随机) │
└──────────┘ └──────────────────────┘
用例: 流水号、批次号、临时编号(时间可读 + 简易去重)
// 默认格式 yyyyMMddHHmmss + 4 位随机数
string noStr = IdGenerator.NoStr();
// → "202602231508451234"
long noLong = IdGenerator.No();
// → 202602231508459876
// 自定义时间格式
string shortNo = IdGenerator.NoStr("yyMMddHHmm");
// → "2602231508" + 随机后缀
⚠️ 使用注意:
No/NoStr使用共享的static Random+ 自增计数器_sn生成后缀,单实例内线程安全。该格式非 Snowflake ID,不保证跨实例唯一性。
场景四:三种算法模式切换
// 模式 1(默认): 雪花漂移算法 — 时钟回拨自动补偿,推荐用于生产环境
IdGenerator.Configure(new IdGeneratorOptions
{
WorkerId = 1,
Method = 1 // 漂移补偿
});
// 模式 2: 传统雪花算法 — 严格单调递增,遇到时钟回拨直接抛出异常
IdGenerator.Configure(new IdGeneratorOptions
{
WorkerId = 2,
Method = 2 // 传统雪花
});
// 模式 3: 漂移算法 + DataCenter + 秒级时间戳 — 适用于多数据中心、低精度场景
IdGenerator.Configure(new IdGeneratorOptions
{
WorkerId = 1,
DataCenterId = 3,
DataCenterIdBitLength = 2,
TimestampType = 1, // 秒级时间戳
Method = 1 // 漂移补偿(Method=1 时自动选择 M3 实现)
});
| 模式 | 类 | 时钟回拨策略 | 适用场景 |
|---|---|---|---|
| Method 1 | SnowWorkerM1 |
漂移补偿(借用下一毫秒 + 回拨次序 1~4) | 生产环境(推荐) |
| Method 2 | SnowWorkerM2 |
抛出异常 | 严格时钟同步环境 |
| Method 3 | SnowWorkerM3 |
漂移补偿 + DataCenter + 秒级时间戳 | 多数据中心 / 低精度 |
⚠️ 注意: 当
Method=1且DataCenterIdBitLength > 0或TimestampType = 1时,自动选择SnowWorkerM3实现。
场景五:通过 IConfiguration 配置
// appsettings.json
{
"IdGenerator": {
"WorkerId": "3",
"SeqBitLength": "8"
}
}
// 初始化
var builder = WebApplication.CreateBuilder(args);
IdGenerator.Configure(builder.Configuration);
❗ Bug 警告:
ConfigureOption.Configure(IConfiguration)在第 61 行存在赋值错误——当SeqBitLength解析失败时执行的逻辑是workerId = 6而非seqBitLength = 6。这意味着:如果你的配置文件中未显式提供SeqBitLength,workerId将被错误覆盖为 6,而seqBitLength保持默认值 6。请务必在配置文件中同时提供WorkerId和SeqBitLength,避免触发此 Bug。
场景六:使用 IIdGenerator 接口
// 获取底层 IIdGenerator 实例
IIdGenerator generator = IdGenerator.IdGenInstance;
// 生成 ID
long id = generator.NewLong();
// 注册漂移事件回调(示例)
generator.GenIdActionAsync = (arg) =>
{
Console.WriteLine(
$"ActionType={arg.ActionType}, WorkerId={arg.WorkerId}, " +
$"TimeTick={arg.TimeTick}, OverCostCount={arg.OverCostCountInOneTerm}");
};
⚠️ 死代码警告:
SnowWorkerM1中的BeginOverCostAction、EndOverCostAction、BeginTurnBackAction、EndTurnBackAction四个方法开头均有return;语句,导致GenIdActionAsync回调永远无法被触发。注册的回调不会收到任何通知。在修复前,不要依赖回调机制来监控 ID 生成状态。
⚙️ 配置选项详解
IdGeneratorOptions
| 参数 | 类型 | 约束 | 默认值 | 说明 |
|---|---|---|---|---|
Method |
short |
1 / 2 | 1 |
算法模式:1=漂移补偿,2=传统雪花 |
BaseTime |
DateTime |
不能超过当前系统时间 | 2020-02-20 02:20:02.020 (UTC) |
基准时间(UTC),ID 的时间戳部分为相对此时间的偏移 |
WorkerId |
ushort |
0 ~ 2^WorkerIdBitLength-1 | 0 |
机器码,必须全局唯一(或同 DataCenterId 内唯一) |
WorkerIdBitLength |
byte |
[1, 19](实际 ≤16) | 6 |
机器码位长,决定 WorkerId 最大值 |
SeqBitLength |
byte |
[3, 21](建议 ≥4) | 6 |
序列数位长,决定每毫秒基础生成 ID 个数 |
MaxSeqNumber |
int |
[MinSeqNumber, 2^SeqBitLength-1] | 0(= 2^SeqBitLength-1) |
最大序列数,0 表示取理论最大值 |
MinSeqNumber |
ushort |
[5, MaxSeqNumber] | 5 |
最小序列数,0-4 为保留位(回拨/手工预留) |
TopOverCostCount |
int |
推荐 500~10000 | 2000 |
最大漂移次数,超出后等待时间对齐 |
DataCenterId |
uint |
0 ~ 2^DataCenterIdBitLength-1 | 0 |
数据中心 ID,Method 3 使用 |
DataCenterIdBitLength |
byte |
— | 0 |
数据中心 ID 位长,0 表示不使用 |
TimestampType |
byte |
0(毫秒)/ 1(秒) | 0 |
时间戳精度,秒级时放大时间位长到 31 |
位长约束
WorkerIdBitLength + DataCenterIdBitLength + SeqBitLength ≤ 22(毫秒模式)
WorkerIdBitLength + DataCenterIdBitLength + SeqBitLength ≤ 31(秒级模式)
Configure 重载
| 重载 | 说明 |
|---|---|
Configure(IdGeneratorOptions) |
完整配置,传入所有选项 |
Configure(ushort workerId, byte seqBitLength) |
精简配置,仅设置 WorkerId 和 SeqBitLength |
Configure(IConfiguration) |
从 IConfiguration 读取 "IdGenerator" 节点 |
🛡️ 错误处理与日志
异常体系
DefaultIdGenerator 构造函数在参数不合法时抛出 ApplicationException(含本地化消息):
// 未调用 Configure 时自动初始化为 WorkerId=0(不抛异常)
long id = IdGenerator.Id; // ✅ 自动初始化
// WorkerId 超出位长限制 → ApplicationException
IdGenerator.Configure(new IdGeneratorOptions { WorkerId = 64, WorkerIdBitLength = 6 });
// → "workerid错误。(范围:[0,63])"
// BaseTime 超过当前时间 → ApplicationException
IdGenerator.Configure(new IdGeneratorOptions { BaseTime = DateTime.UtcNow.AddDays(1) });
// → "basetime错误。"
// WorkerIdBitLength = 0 → ApplicationException
IdGenerator.Configure(new IdGeneratorOptions { WorkerIdBitLength = 0 });
// → "workeridbitlength错误。(范围:[1,21])"
Method 2 时钟回拨异常
IdGenerator.Configure(new IdGeneratorOptions { Method = 2, WorkerId = 1 });
try
{
long id = IdGenerator.Id;
}
catch (Exception ex)
{
// "xxx毫秒的时间错误" — Method 2 遇到时钟回拨时抛出
_logger.LogError(ex, "Snowflake 时钟回拨,生成的 ID 可能重复");
// ⚠️ 此时应切换到 Method 1 或暂停服务等待时钟恢复
}
推荐日志模式
using Microsoft.Extensions.Logging;
public class IdGeneratorService
{
private readonly ILogger<IdGeneratorService> _logger;
public IdGeneratorService(ILogger<IdGeneratorService> logger) => _logger = logger;
/// <summary>
/// 带日志的 ID 生成器初始化
/// </summary>
public void Initialize(ushort workerId, byte seqBitLength = 6)
{
try
{
IdGenerator.Configure(workerId, seqBitLength);
_logger.LogInformation(
"ExIdGen 初始化成功: WorkerId={WorkerId}, SeqBitLength={SeqBitLength}",
workerId, seqBitLength);
}
catch (ApplicationException ex)
{
_logger.LogError(ex, "ExIdGen 初始化失败,参数校验未通过");
throw;
}
}
/// <summary>
/// 安全生成 ID(Method 2 时钟回拨兜底)
/// </summary>
public long NextIdSafe()
{
try
{
return IdGenerator.Id;
}
catch (Exception ex) when (ex.Message.Contains("毫秒的时间错误"))
{
_logger.LogWarning(ex, "传统雪花模式遭遇时钟回拨,考虑切换到 Method=1");
throw;
}
}
}
🧵 线程安全
| 组件 | 线程安全 | 说明 |
|---|---|---|
IdGenerator.Id |
⚠️ 加锁保证 | SnowWorkerM1.NextId() 使用 lock(_SyncLock) 保证临界区互斥 |
IdGenerator.IdStr |
⚠️ 加锁保证 | 委托给 NextId(),同上 |
IdGenerator.No / NoStr |
✅ 加锁保证 | 共享 static Random + 独立 lock,线程安全 |
ConfigureOption.Configure |
✅ 是 | NextId() 惰性初始化使用双重检查锁(lock(_initLock)),线程安全 |
SnowWorkerM1 / M2 / M3 |
⚠️ 全局锁 | _SyncLock 是 static readonly——所有实例共享同一把锁,多实例也串行执行 |
DefaultIdGenerator |
⚠️ 是 | 实例安全,但其委托的 _SnowWorker.NextId() 受全局锁限制 |
i18n |
✅ 是 | ResourceManager 线程安全 |
⚠️ 重要: 全局锁限制:
SnowWorkerM1._SyncLock是static readonly,所有DefaultIdGenerator实例共享同一把锁。多实例场景下 ID 生成完全串行化。如需更高吞吐量,请在应用层做 worker 分片。
// ✅ 正确: 启动时配置
public static void Main(string[] args)
{
IdGenerator.Configure(workerId: 1, seqBitLength: 6); // ← 先配置
var app = BuildApp(args);
app.Run();
}
// ❌ 错误: 延迟配置(并发访问可能创建多个实例)
Task.Run(() => IdGenerator.Configure(1, 6));
Task.Run(() => { var id = IdGenerator.Id; }); // ← 竞态!
⚠️ 重要(2): 全局锁:
SnowWorkerM1._SyncLock被声明为protected static object _SyncLock = new object()。这意味着即使你创建了多个DefaultIdGenerator实例(不同的WorkerId),它们仍共享同一把锁,所有 ID 生成被全局串行化。这是设计权衡——确保时间戳和序列号在进程内绝对单调递增,但是以吞吐量为代价。
⚠️ 重要(3): 不要声称"无锁"。
NextId()明确使用lock(_SyncLock)同步,且No/NoStr也使用独立lock。这不是无锁实现。
📊 算法速查表
| 类 | 方法 | 输入 | 输出 | 用途 |
|---|---|---|---|---|
IdGenerator.Id |
static getter |
无 | long (64-bit) |
数据库主键、全局唯一 ID |
IdGenerator.IdStr |
static getter |
string prefix |
string |
人类可读的业务编号 |
IdGenerator.No |
static getter |
string format |
long |
时间可读的长整型流水号 |
IdGenerator.NoStr |
static getter |
string format |
string |
时间可读的字符串流水号 |
IIdGenerator.NewLong |
实例方法 | 无 | long (64-bit) |
通过接口直接访问底层生成器 |
IdGenerator.Configure |
static |
options / workerId+seq / IConfiguration |
void |
初始化/重配置 ID 生成器 |
ID 结构(Method 1,默认位长配置)
┌─────────────────────────────────────────────────────────────┐
│ 63 ......................... 12 │ 11 .... 6 │ 5 ........ 0 │
│ 时间戳偏移 (52 bit) │ WorkerId │ 序列号 │
│ │ (6 bit) │ (6 bit) │
└─────────────────────────────────────────────────────────────┘
WorkerIdBitLength=6, SeqBitLength=6, TimestampShift=12
🌍 国际化
错误消息支持以下语言,根据 CultureInfo.CurrentUICulture 自动切换:
| 语言 | 区域代码 |
|---|---|
| 简体中文 | zh-CN |
| 繁体中文(台湾) | zh-TW |
| 粤语(香港) | zh-HK |
| 英语 | en-US |
| 法语 | fr-FR |
| 日语 | ja-JP |
| 越南语 | vi-VN |
// 当前线程 UI 文化为 fr-FR 时:
// ApplicationException → 对应法语的 "basetime错误。"(具体内容取决于 .resx 翻译)
IdGenerator.Configure(new IdGeneratorOptions { BaseTime = DateTime.UtcNow.AddDays(1) });
可通过
I18nConverter.ConvertResxToJson()将资源内容导出为 JSON(需NET5_0_OR_GREATER)。
🗺️ 版本迁移指南
从手动管理 Snowflake 迁移
| 旧代码模式 | 迁移到 RuoVea.ExIdGen |
|---|---|
手动实现 Snowflake + Stopwatch / DateTime 计算 |
IdGenerator.Id |
手动维护 AtomicLong 序列号 + 时钟回拨处理 |
IdGenerator.Configure(workerId, seqBitLength) |
| appsettings.json + 手动解析 WorkerId | IdGenerator.Configure(IConfiguration) |
| GUID / UUID 作为分布式 ID | IdGenerator.Id(64-bit,体积减半,有序递增) |
v8.0.x → v10.0.x
- API 无变化。v10.0.x 仅在
net10.0TFM 上编译,所有公开 API 签名保持一致。 - 依赖
Microsoft.Extensions.Configuration.Binder版本从8.0.2升级到10.0.8。
📄 License
MIT License © RuoVea
原始算法版权:yitter/idgenerator (MIT)
🔗 相关资源: NuGet Gallery · 问题反馈
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Configuration.Binder (>= 10.0.8)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on RuoVea.ExIdGen:
| Package | Downloads |
|---|---|
|
RuoVea.ExSugar
Sqlsugar扩展 快速注入,支持简体中文、繁体中文、粤语、日语、法语、英语.使用方式:service.AddSqlsugar();继承RestFulLog 重写异常日志,操作日志,差异日志 |
|
|
RuoVea.ExWeb
CorsUrls、IPLimit、SafeIps、Jwt 配置 |
|
|
RuoVea.QuartzNetUI
QuartzNet UI界面 执行脚本地址:https://gitee.com/starry123/ruovea-quartznet-ui/tree/develop/Doc/Sql |
|
|
RuoVea.KM
RuoVea.KM 提供完整的授权管理系统: - **LicenseInfo**:授权信息实体类,包含授权ID、客户名称、绑定机器指纹、有效期等属性 - **LicenseManager**:授权管理通用类,提供授权码生成、验证、激活等功能 - **MachineFingerprint**:机器硬件指纹生成器,基于CPU、硬盘、MAC地址和主板序列号 该库提供了简单易用的 API 接口,支持 .NET 5/6/7/8/9/10,适用于各种国密加密和授权管理场景 |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.0.3 | 220 | 6/24/2026 |
| 10.0.0.2 | 508 | 5/28/2026 |
| 10.0.0.1 | 916 | 11/21/2025 |
| 9.0.0.1 | 1,589 | 11/21/2025 |
| 9.0.0 | 607 | 7/25/2025 |
| 8.0.1.2 | 347 | 6/24/2026 |
| 8.0.1.1 | 4,398 | 11/21/2025 |
| 8.0.1 | 6,338 | 8/26/2024 |
| 8.0.0 | 565 | 11/24/2023 |
| 7.0.1.1 | 4,476 | 11/21/2025 |
| 7.0.1 | 7,591 | 8/26/2024 |
| 7.0.0 | 305 | 7/23/2024 |
| 6.0.1.2 | 5,391 | 11/21/2025 |
| 6.0.1 | 15,795 | 8/26/2024 |
| 5.0.3.2 | 132 | 5/28/2026 |
| 5.0.3.1 | 650 | 11/21/2025 |
| 5.0.3 | 691 | 8/26/2024 |
| 2.1.1.2 | 423 | 11/21/2025 |
| 2.0.0.1 | 433 | 11/21/2025 |
| 2.0.0 | 236 | 9/22/2024 |