跳到主要内容
版本:3.0.0

ID生成器

这页对应 3.x 里的 ID 生成使用方式,核心组件是 ID 生成器(Aegis.IdGenerator)。如果模板编号需要在多实例间共享流水号,还要继续接 Redis ID 生成提供程序(Aegis.IdGenerator.Provider.Redis)

先记住这组能力的边界

当前 ID 生成体系主要分成两类:

  • 雪花 ID:返回 long
  • 模板 ID:返回带业务格式的字符串

最简单的判断方式是:

  • 只要唯一数字主键,用雪花 ID
  • 只要带前缀、日期、流水号的业务单号,用模板 ID

最常用的接入方式

只要雪花 ID

{
"Components": {
"Services": [
"IdGenerator.SnowflakeId"
]
}
}

雪花 ID 和模板 ID 都要

{
"Components": {
"Services": [
"IdGenerator"
]
}
}

雪花 ID 怎么配

{
"IdGenerator": {
"WorkerId": 2,
"WorkerIdLength": 5,
"IndexLength": 8
}
}

这几个配置项分别是什么意思

配置项作用
WorkerId当前节点编号
WorkerIdLength节点编号位数
IndexLength同一时间窗口内的流水号位数
WorkerIdProviderWorkerId 提供器类型名
StartTimeStamp雪花算法起始时间

最常见的使用方式

public class SnowflakeService
{
private readonly IIdGenerator _idGenerator;

public SnowflakeService(IIdGenerator idGenerator)
{
_idGenerator = idGenerator;
}

public long CreateId()
{
return _idGenerator.NextId();
}
}

使用雪花 ID 时最重要的一条规则

多实例场景下,每个实例的 WorkerId 都必须唯一。
这一点如果配错,后面的唯一性就没有保障。

模板 ID 怎么接

模板 ID 至少需要三样东西:

  1. 模板能力本身
  2. 模板提供者
  3. 如果是多实例,再补 Redis 序号容器

第一步:启用模板能力

{
"Components": {
"Services": [
"IdGenerator.TemplateId"
]
}
}

如果你已经启用了总入口 IdGenerator,这一步可以不用再单独配。

第二步:注册模板提供者

services.AddIdTemplateProvider<TemplateProvider>();

第三步:实现模板提供者

public class TemplateProvider : IIdTemplateProvider
{
public async Task<IdTemplate[]> GetIdTemplates()
{
var template = new IdTemplate
{
Key = "A1",
PaddingChar = '0',
DateReset = true,
CanReturn = true,
FormatString = "Test{Date}{SerialNum}",
SerialNumLength = 6
};

return new[] { template };
}
}

IdTemplate 最常见字段怎么理解

字段作用
Key模板键
FormatString编号格式,如 Test{Date}{SerialNum}
SerialNumLength流水号长度
PaddingChar流水号填充字符
DateReset是否按日期重置流水
CanReturn是否允许归还编号
MinSerialNum最小流水号
MaxSerialNum最大流水号
RecoveryTime归还时间窗口

模板 ID 怎么用

获取单个编号

var id = _templateIdGenerator.GetId("A1");

批量获取编号

var ids = _templateIdGenerator.GetIds("A1", 30);

归还和确认编号

_templateIdGenerator.ReleaseId("A1", id);
_templateIdGenerator.ConfirmId("A1", id);
_templateIdGenerator.ConfirmIds("A1", ids);

动态新增和移除模板

_idTemplateManager.Add(new IdTemplate
{
Key = "A1",
CanReturn = true,
FormatString = "ORD{Date}{SerialNum}",
DateReset = true,
PaddingChar = '0',
SerialNumLength = 6
});

_idTemplateManager.Remove("A1");

什么情况下要继续接 Redis 容器

只要进入下面这些场景,就建议把模板流水号切到 Redis:

  • 多实例部署
  • 模板编号要跨实例共享
  • 需要归还和重用编号
  • 不希望单机重启后序号行为失控

最常见接法如下:

services.AddRedisSource<AegisRedisSource>(
ConfigManager.Get<RedisOptions>("Redis"));

services.AddIdRedisContainer<AegisRedisSource>();
services.AddIdTemplateProvider<TemplateProvider>();

接入完成后怎么确认成功

你至少应该确认这些点:

  • Component.deps.json 已启用正确的 ID 生成组件声明
  • 雪花模式下可以稳定注入 IIdGenerator
  • 模板模式下可以稳定注入 ITemplateIdGenerator
  • 模板 Key 能找到对应规则
  • 多实例场景下模板编号不会重复

常见问题

为什么只能拿到雪花 ID,拿不到模板能力

通常是只启用了 IdGenerator.SnowflakeId,没有启用 IdGeneratorIdGenerator.TemplateId

为什么模板已经注册了,但 GetId("A1") 还是失败

优先检查:

  1. 模板提供者是否真的注册成功
  2. 返回的 Key 是否就是 A1
  3. 当前模板能力是否已经启用

为什么模板编号在多实例下重复或错乱

这通常说明模板流水号还没有切到 Redis 容器。

推荐阅读顺序

  1. ID 生成器(Aegis.IdGenerator)
  2. Redis ID 生成提供程序(Aegis.IdGenerator.Provider.Redis)
  3. Redis