我一直在浏览网络,试图找到一种解决方案,使我们能够在区域分布式环境中生成唯一ID。
我查看了以下选项(其中包括):
SNOWFLAKE(通过Twitter)
UUID
像MYSQL一样的关系数据库中的自动识别
非关系数据库中的自动识别类似
假设我们在5个不同地区(非洲,欧洲,亚洲,美洲和大洋洲)拥有由10个Couchbase节点和10个应用节点组成的集群。这是为了确保从最靠近用户的位置提供内容(以提高速度)并确保在发生灾难时的冗余等。
现在,任务是生成在复制(和平衡)发生时不会发生冲突的ID,我认为这可以通过3个步骤实现:
第1步
将为所有区域分配整数ID(唯一标识符):
第2步
为添加到群集的每个应用程序节点分配一个ID,记住一个群集中最多可能有99 999个服务器(尽管我怀疑:这是一个安全的预防措施)。这看起来像这样(假IP):
请注意,所有这些都在同一个群集中,这意味着您可以在每个区域拥有节点00001。
第3步
对于插入数据库的每条记录,将使用递增的ID来识别它,这就是它的工作方式:
Couchbase提供了一种增量功能,可用于在群集内部创建ID。为确保冗余,将在群集中创建3个副本。由于它们位于同一个地方,我认为应该可以安全地假设,除非整个群集关闭,否则其中一个节点将可用,否则可以增加一些副本。
将所有内容整合在一起
假设用户正在从欧洲注册: 提供请求的应用程序节点将获取区域代码(在这种情况下 4 ),获取自己的ID(例如 00005 ),然后获取递增的ID( 1 )来自Couchbase(来自同一群集)。
我们最终得到3个组件:4, 00005,1
。现在,要从中创建ID,我们可以将这些组件加入4.00005.1
。为了使它更好(我对此不太确定),我们可以连接(而不是添加它们)组件,最终得到:4000051
。
在代码中,这看起来像这样:
$id = '4'.'00005'.'1';
注意:不是$id = 4+00005+1;
。
赞成
缺点
我知道每个解决方案都有缺陷,可能还有我们在表面上看到的更多。你能发现这整个方法的任何问题吗?
提前感谢您的帮助: - )
修改
正如@DaveRandom建议的那样,我们可以添加第4步:
第4步
我们可以生成一个随机数并将其附加到ID以防止可预测性。实际上,你最终会得到这样的结论:
4000051357
而非4000051
。
答案 0 :(得分:1)
您担心ID有两个原因:
从第二个问题开始,外观。虽然UUID在标识符方面肯定不是一个很好的美,但是当您在复杂的数据中心(或数据中心)中引入真正唯一的数字时,回报会逐渐减少。我不相信,当在Web应用程序的URL中使用长数字而不是UUID时,应用程序的感知会发生巨大变化。理想情况下,两者都不会被显示,ID
只会通过Ajax请求等发送。虽然一个漂亮,干净的令人难忘的URL是可取的,但它从来没有阻止我在亚马逊购物(他们有绝对可怕的URL) 。 :)
即使你的提议,标识符虽然它们的字符数比UUID短,但它们不比UUID更令人难忘。因此,外观可能仍有争议。
谈到第一点......,是的,有一些情况下UUID已知会产生冲突。虽然这不应该在一个配置合理且一致的架构中发生,但我可以看到它会如何发生(但我个人对此并不那么担心)。
所以,如果你在讨论替代方案,我会成为MongoDB ObjectId
的简单性及其生成ID时避免重复的技术的粉丝。完整文档为here。快速相关部分在几个方面与您的潜在设计类似:
ObjectId是一个12字节的BSON类型,使用:
构造时间戳通常可用于排序。计算机标识符与具有唯一ID的应用程序服务器类似。进程id只是附加的熵,最后为了防止冲突,只要时间戳与上次生成ObjectId的时间戳相同,就会有一个自动递增的计数器(这样可以快速创建ObjectIds)。 ObjectId
可以在客户端或数据库上生成。此外,ObjectIds占用的字节数比UUID少(但只有4个)。当然,您无法使用时间戳并丢弃4个字节。
为了澄清,我不是建议您使用MongoDB,而是受其用于ID生成的技术的启发。
所以,我认为您的解决方案很不错(也许您希望受到MongoDB的独特ID实现的启发)并且可行。至于你是否需要这样做,我认为这是一个只有你能回答的问题。
答案 1 :(得分:1)
我认为这看起来很稳固。每个区域都保持一致性,如果使用XDCR,则不会发生冲突。 INCR在集群中是原子的,因此您不会遇到任何问题。您实际上不需要将机器代码作为其中的一部分。如果某个区域内的所有应用服务器都连接到同一个群集,则将其中的00001部分中断是无关紧要的。如果由于其他原因(某种分析)对您有用,那么无论如何都是如此,但没有必要。
所以它可以简单地为'4'。 1'(使用你的例子)
你能举个例子说明你需要什么样的“排序”吗?
首先:添加熵的一个缺点(我不确定你为什么需要它),你不能轻易地迭代ID集合。
例如:如果您的ID是1-100,您将从计数器键上的简单GET查询中获知,您可以按组分配任务,此任务需要1-10,接下来的11-20等等,工人可以并行执行。如果添加熵,则需要使用Map / Reduce View来提取集合,这样就会失去键值模式的好处。
第二:由于您关注可读性,因此添加文档/对象类型标识符也很有价值,这可以在Map / Reduce Views中使用(或者您可以使用json关键来识别那个)。
前:'你:'。 '4'。 '1'
如果您在外部引用ID,您可能希望以其他方式隐藏。如果你需要一个例子,请告诉我,我可以用你能做的事情来补充我的答案。