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

时间:2009-12-23 16:23:35

标签: algorithm language-agnostic unique uniqueidentifier

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

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

硬要求

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

软要求

  • 我们希望从日历年和/或月开始。由于这确实浪费了很多熵,我不介意妥协或完全废弃它(如有必要)。
  • 从特定计算机生成的ID应该是顺序显示的。
  • 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。我之所以在SO上提出这个问题的原因,是因为我真的想尝试在那里加入人类可读的年/月或者编写一些关于源机器的信息,或两者兼而有之。

我希望有人可以帮助对这些软性要求做出妥协......或者解释为什么在给定其他要求的情况下,没有人可以做到这一点。

(P.S。我的“原生”语言是C#,但如果有人有任何好主意,任何语言甚至伪代码的代码都可以。)

更新

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

10 个答案:

答案 0 :(得分:4)

  

“我在这里问这个问题的原因   所以,是因为我真的很想   要么尝试合并   人类可读的年/月在那里或   编码一些关于的信息   源机器,或两者兼而有之。“

首先让我说我之前已经处理过这个问题,并且尝试将有用的信息存储到序列号中是一个长期不好的想法。设备序列号应该没有意义。就像数据库记录的主键应该没有意义一样。

第二个你开始尝试将真实数据放入序列号中,你只是将BUSINESS LOGIC抛入其中,你将被迫像任何其他代码一样维护它。未来你会恨你过去。相信我。 ; O)

如果您尝试存储日期/时间值,那么您将浪费具有无效时间/日期的数字空间。例如,您在月份字段中永远不会有大于12的内容。

一个直的纪元/单位时间计数器会更好,但对于每分钟只生成几个id的机器,你仍然会浪费很多空间。

12位不是很大的空间。查看Wikipedia上的VIN页面。只有少数制造商的空间,只有几千辆汽车。他们现在正在重复使用VIN,因为它们通过在其中包含意义而耗尽了空间。

http://en.wikipedia.org/wiki/VIN

这并不是说序列号中的所有含义都不好,只是严格限制它以确保数字不会发生碰撞。

像这样......

  • 职位1-3:999机器
  • 位置4-12:连续数字

你需要避免碰撞 ALL 。如果你添加一个位置数字,那么当你到达11个地点时就会被搞砸。

对不起,如果这听起来像个咆哮。我处理了很多制造电子产品和各种机加工零件。除非有大量可用空间或次要标签(哇 - 提供之前提到的必要id空间),否则它永远不会长期结束。

答案 1 :(得分:3)

安装软件时,还要安装包含唯一数字ID的machi id文件/注册表项。由于您只有几台机器,因此不应超过3或4位数。使用这些作为MS数字。从1开始按顺序生成剩余数字。

答案 2 :(得分: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

示例:来自0912113201的计算机的ID = 01

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

yyyy = four-digit year
MM = two-digit month
ID = machine-specific ID
xxxx = sequentially-incremented integer

示例:来自200912010001的计算机的ID = 01

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

这两个都符合您的要求时间戳/机器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());

输出:

200912010000
200912010001

答案 3 :(得分:1)

我正在收集你正在为Windows开发(重新:关于“MSI / EXE”的评论以回应Jason的回答)。因此,您可以通过WMI或类似方式获取一些独特的硬件属性(例如处理器或HDD序列号,或NIC的MAC地址),以基于唯一的计算机ID。另一种方法可能是使用您自己开发的硬件的唯一序列号(如果有的话)。

这很可能比您需要的时间长,因此您可能会截断或散列它以将其减少到(例如)16位左右,并将其用作您的计算机ID。显然,这可能会导致冲突,但是少量的机器(~100)意味着这是不太可能的,并且使用加密哈希的截断输出(比如MD5)会使这种情况更加糟糕。

然后,由于您拥有(最可能是唯一的)计算机ID,因此您可以使用其他答案列出的方法生成基本上唯一的ID。

答案 4 :(得分:0)

24小时内有864000个100ms的刻度,因此将其添加到日期可能会起作用09.12.24.86400.0,但是您必须丢失世纪以适应12位数,并且您没有机器ID的空间

答案 5 :(得分:0)

理念第一:

YYMMDDmmnnnn

,其中

YY is two digit year
MM is two digit month
DD is two digit day
mm is a two digit code unique to that machine (00 - 99)
nnnn is a sequential four digit code for that machine on that day.

~~

第二个想法:

mmmmnnnnnnnn

哪里

mmmm is four digit code unique to the machine
nnnnnnnn is a sequential number.

答案 6 :(得分:0)

我的建议是在一个id中组合多种方法。例如:以两年数字,两个月数字开头,然后生成一个随机数,时间作为下几个数字的种子,然后是最后一对数的唯一机器ID。或类似的东西。

答案 7 :(得分:0)

每台机器都获得DDNNN的起始ID,其中DD是唯一的机器标识符,NNN是该机器当天生成的当前标识符。每台机器都会跟踪它在特定日期生成的ID,并在需要新的ID时通过将最后一个增加1来分配下一个。它会在每天开始时将其计数器重置为0。 YYYYDOY日期前置于每台机器生成的数字(4位数年份,3位数日期)。由于机器标识符是唯一的,因此该数字是唯一的。

如果您需要更多空间用于更多机器,您可以从年份中删除千禧年并为机器ID添加一个数字:YYYDOYDDDNNN。

答案 8 :(得分:0)

“单台机器不会每隔5分钟左右生成ID”

假设这是真的,那么只需使用时间戳。 (32位Unix时间有10位小数,但会在2038年用完)

但我认为假设不会发生碰撞相当乐观。

“从特定计算机生成的ID应该是顺序显示的。”

然后您唯一的选择是使用序列号。

哪个似乎与您在后来的约束中所说的不匹配?

连接节点标识的填充版本以获取整个集群中的唯一值。

答案 9 :(得分:-1)

将机器的MAC地址用作MACHINE ID。您可以使用它来编码时间戳,即通过XOR编码,或者您可以将其添加/添加到生成的序列化代码中。