流星ID防撞缩短

时间:2019-05-19 09:31:39

标签: meteor random entropy

Meteor使用其内部Random包为文档生成Mongo-Ids,其中used set of characters定义为:

var UNMISTAKABLE_CHARS = "23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz";

Random.id的{​​{3}}也指出:

  

返回唯一的标识符,例如"Jjwjg6gouWLXhMGKW",在全球范围内很可能是唯一的。

,它是为ID的默认长度(17个字符; UNMISTAKABLE_CHARS中的每个字符)定义的。

现在,我只想使用Id的前N个字符来缩短我的网址(其中包括Id,以动态加载需要特定文档(由Id确定)的页面)。

如果我的原始ID是

`v5sw59HEdX9KM5KQE`

我想举个例子(在这里考虑一个完全随机选择的N = 5):

{
  _id:"v5sw59HEdX9KM5KQE",
  short: "v5sw5"
}

作为文档架构,并使用{ short }作为我的Mongo.Collection中的查询通过此ID提取相应的文档。

现在我的问题是如果要考虑5000到10000之间的文档量(因此IDs),那么有多少个字符可以防止冲突

注意:我前面有一些熵计算工具,所有这些值(字符集,原始ID的长度,文档数)都在我眼前,但我不知道如何接线所有这一切都可以安全地计算出N。

3 个答案:

答案 0 :(得分:2)

至少在理论上,随机生成标识符已经冒了生成重复标识符的风险。对于默认的MongoID长度(假设其中有55 17 个),在生成了将近731156亿个随机MongoID之后,存在重复的MongoID的机会达到50%(请参阅“ Birthday problem”) ,因此在大多数情况下,实际上重复的机会微不足道。

缩短随机标识符将使碰撞问题更加严重。在这种情况下,对于5个字符的ID长度(导致55 5 或503284375个不同的ID),仅生成约26415个随机ID之后,重复的MongoID的机会达到50%。

由于似乎您无法像控制缩短的"unique IDs"一样容易地控制MongoID的生成方式,因此您可以做的一件事是:

  • 创建一个文档,该文档将每个MongoID分配给一个唯一分配的数字(例如单调递增的计数器)。
  • 要使通过这种方式分配的数字看起来“随机”,请将每个数字馈送到所谓的“全周期”线性同余生成器,以在生成器的周期内获得唯一但“随机”的数字。
  • 数字(类似于MongoID字符串编码)可以用作您的简短标识符。

但是请考虑您是否真的希望这种方式创建的短标识符是可预测的。使用短标识符几乎无法实现此可预测性目标。

如果您希望使用缩短的MongoID,请参阅“ Birthday problem”,了解可用来估计允许随机数发生碰撞的随机数的公式。


有关Meteor如何生成MongoID的更多信息,另请参见this question;它的答案之一包括一种让MongoDB在服务器上生成MongoID而不是让Meteor在客户端上生成MongoID的方法。同样,Meteor似乎在将它们生成的MongoID插入文档之前也不会对其进行唯一性检查。

答案 1 :(得分:2)

如果我的理解正确,除了为您的文档_id生成正常的17个字符长的id之外,您还希望使用较短的ID,这样通常在包含该ID的情况下,URL看起来就不会那么吓人了。

在您的示例中,您截断了ID,因此在较短的ID与原始文档ID之间建立了显式关联。

这听起来像git short commit hash:How does Git(Hub) handle possible collisions from short SHAs?

您可以遵循类似的路径,即首先确定合理的初始默认长度,以避免可能的冲突(如Peter O.的回答中所述),但显式检查服务器端的唯一性并增加任何长度新的缩短版本,以防发生冲突,直到再次变得唯一。

答案 2 :(得分:2)

我认为,如果要避免在小集合上发生冲突,那么不要要使用随机ID,但是要么使用完全确定性ID,要么至少将随机性降低到某种程度更有控制力。按照这些原则,您可以考虑的另一种选择是使用MONGO for idGeneration in your collection。这些ID是在known recipe之后生成的。因此,您可以使用该ID的1-4和12个字符,并且只要在同一秒内创建的文档数不超过N个,就可以保证没有哈希冲突,其中N是MongoID中使用的字符数(即不知道一手掌握)。