生成一个非全球唯一的标识符

Aar*_*ght 8 language-agnostic algorithm unique uniqueidentifier

我发现了许多关于生成UID的不同问题,但据我所知,我的要求有点独特(ha).

总结一下:我需要生成一个非常短的ID,它是"本地"唯一的,但不必是"全局"或"普遍"唯一的.约束不仅仅基于美学或空间问题,而是由于这实际上被用作硬件标签,并且这受到硬件约束的约束.以下是规格:

硬要求

  • ID必须只包含十进制数字(基础数据是BCD);
  • ID的最大长度为12个字符(数字).
  • 必须离线生成- 数据库/ Web连接并不总是可用!

软要求

  • 我们希望它从日历年和/或月开始.因为这确实浪费了很多熵,我不介意妥协或完全废弃它(如果必要的话).
  • 从特定计算机生成的ID应该是顺序出现的.
  • 编号可能不会有机器排序-例如,它完全罚款机1吐出[123000,124000,125000],和机器2吐出[123500,123600,124100].
  • 然而,在集体意义上越顺序,越好.像[200912000001,200912000002,200912000003,...]这样的一组ID将是完美的,尽管这显然不能跨多台机器扩展.

使用场景:

  • 该方案范围内的ID最多可由10台,甚至100台不同的机器生成.
  • 生成的ID总数不会超过几百万.
  • 并发性极低.单个机器不会比每5分钟左右更频繁地生成ID.此外,一次最多不超过5台机器将在同一小时甚至同一天内生成ID.我希望在给定的机器上一天内生成的ID少于100个,所有机器的生成少于500个.
  • 少数机器(3-5)最有可能负责生成超过80%的ID.

我知道可以使用少于12个十进制数字将时间戳编码为100 ms甚至10 ms精度,这足以保证此应用程序的"足够唯一"ID.我在这里问这个问题的原因是因为我真的想要尝试在那里加入人类可读的年/月或编码关于源机器的一些信息,或两者兼而有之.

我希望有人可以帮助在这些软性要求上做出妥协......或者解释为什么在给出其他要求的情况下它们都不可能.

(PS我的"原生"语言是C#,但如果有人有任何好主意,任何语言或甚至伪代码的代码都可以.)

更新:

既然我已经有机会在它上面睡觉了,我想我实际上要做的是默认使用时间戳编码,并允许单个安装通过定义自己的2或者切换到机器顺序ID 3位机器ID.这样,想要弄乱ID并打包在人类可读信息中的客户可以找出他们自己确保唯一性的方法,我们对滥用不负责任.也许我们通过提供服务器实用程序来帮助处理机器ID,如果它们碰巧正在进行所有在线安装.

jas*_*son 3

怎么样yyMMddhhmmID

yy = two-digit year
MM = two-digit month
dd = two-digit day
hh = two-digit hour (24-hour time)
mm = two-digit minute
ID = machine-specific ID
Run Code Online (Sandbox Code Playgroud)

示例:0912113201来自带有ID = 01.

或者(如果你不喜欢两位数的年份(Y2K 哈哈)),怎么样yyyyMMIDxxxx

yyyy = four-digit year
MM = two-digit month
ID = machine-specific ID
xxxx = sequentially-incremented integer
Run Code Online (Sandbox Code Playgroud)

示例:200912010001来自带有ID = 01.

正如您所说,每台机器每五分钟最多只会生成一个标识符,这为您每月提供了 8,928 (24 * 31 * 60 / 5 = 8928) 个标识符的空间,这将适合xxxx. 如果您需要序列或机器 IDyyy中的额外数字,则可以将年份压缩为三位数年份(例如 009)。xxxx

这两个都符合您要求的时间戳/机器 ID。

我们都喜欢具体的代码:

class Machine {
    public int ID { get; private set; }
    public Machine(int id) {
        ID = id;
    }
}

 class IdentifierGenerator {
    readonly Machine machine;
    int seed;
    const int digits = 4;
    readonly int modulus;
    readonly string seedFormat;
    public IdentifierGenerator(Machine machine) {
        this.machine = machine;
        this.modulus = (int)Math.Pow(10, digits);
        this.seedFormat = new string('0', digits);
    }

    public string Generate() {
        string identifier = DateTime.Now.ToString("yyyyMM") 
                                + machine.ID.ToString("00") 
                                + seed.ToString(seedFormat);
        seed = (seed + 1) % modulus;
        return identifier;
    }
}

Machine m = new Machine(1);
IdentifierGenerator gen = new IdentifierGenerator(m);
Console.WriteLine(gen.Generate());
Console.WriteLine(gen.Generate());
Run Code Online (Sandbox Code Playgroud)

输出:

200912010000
200912010001
Run Code Online (Sandbox Code Playgroud)