建议的解决方案:在分布式环境中生成唯一ID

Sth*_*the 12 php distributed couchbase

我一直在浏览网络,试图找到一个允许我们在区域分布式环境中生成唯一ID的解决方案.

我查看了以下选项(以及其他选项):

SNOWFLAKE(Twitter)

  • 这似乎是一个很好的解决方案,但我不喜欢为了创建ID而必须管理另一个软件的额外复杂性;
  • 它在这个阶段缺乏文档,所以我认为这不是一个好的投资;
  • 节点需要能够使用Zookeeper相互通信(延迟/通信故障怎么样?)

UUID

  • 看看吧:550e8400-e29b-41d4-a716-446655440000 ;
  • 它是一个128位ID;
  • 有一些已知的碰撞(取决于我猜的版本)看到这篇文章.

与MYSQL类似的关系数据库中的自动编码

  • 这似乎是安全的,但不幸的是,我们没有使用关系数据库(可伸缩性首选项);
  • 我们可以为此部署一个MySQL服务器,就像Flickr所做的那样,但同样,这又引入了另一个故障点/瓶颈.还增加了复杂性.

像COUCHBASE一样的非关系数据库中的自动识别

  • 这可能有用,因为我们使用Couchbase作为我们的数据库服务器,但是;
  • 当我们在不同区域有多个集群,延迟问题,网络故障时,这将无效:在某些时候,ID会根据流量的数量发生冲突;

我提出的解决方案(这是我需要帮助的)

假设我们在5个不同的地区(非洲,欧洲,亚洲,美洲和大洋洲)拥有由10个Couchbase节点和10个应用节点组成的集群.这是为了确保从最靠近用户的位置提供内容(以提高速度)并在发生灾难时确保冗余等.

现在,任务是生成在复制(和平衡)发生时不会发生碰撞的ID,我认为这可以通过3个步骤实现:

步骤1

将为所有区域分配整数ID(唯一标识符):

  • 1 - 非洲;
  • 2 - 美国;
  • 3 - 亚洲;
  • 4 - 欧洲;
  • 5 - Ociania.

第2步

为添加到群集的每个应用程序节点分配一个ID,记住一个群集中最多可能有99 999个服务器(尽管我怀疑:这是一个安全的预防措施).这看起来像这样(假IP):

  • 00001 - 192.187.22.14
  • 00002 - 164.254.58.22
  • 00003 - 142.77.22.45
  • 等等.

请注意,所有这些都在同一个集群中,这意味着您可以在每个区域拥有节点00001.

第3步

对于插入数据库的每个记录,将使用递增的ID来标识它,这就是它的工作方式:

Couchbase提供了一个增量功能,我们可以使用它在群集内部创建ID.为确保冗余,将在群集中创建3个副本.由于它们位于同一个地方,我认为应该可以安全地假设除非整个群集关闭,否则将有一个负责此节点的节点,否则可以增加许多副本.

将它们整合在一起

假设用户正在从欧洲注册:服务请求的应用程序节点将获取区域代码(在这种情况下为4),获取自己的ID(比如00005),然后从Couchbase 获取增加的ID(1)(来自相同的)簇).

我们最终有3个组成部分:4, 00005,1.现在,要从中创建ID,我们可以将这些组件加入其中4.00005.1.为了使它更好(我对此不太确定),我们可以连接(而不是添加它们)组件以结束:4000051.

在代码中,这将看起来像这样:

$id = '4'.'00005'.'1';

NB:没有$id = 4+00005+1;.

优点

  • ID看起来比UUID好;
  • 它们看起来很独特.即使另一个区域中的节点生成相同的递增ID并且具有与上述节点ID相同的节点ID,我们总是使用区域代码将它们分开;
  • 它们仍然可以存储为整数(可能是大无符号整数);
  • 它是架构的一部分,没有额外的复杂性.

缺点

  • 没有排序(或者没有)?
  • 这是我需要你输入的地方(大多数)

我知道每个解决方案都有缺陷,可能更多的是我们在表面上看到的.你能发现这整个方法的任何问题吗?

预先感谢您的帮助 :-)

编辑

正如@DaveRandom建议的那样,我们可以添加第4步:

第4步

我们可以生成一个随机数并将其附加到ID以防止可预测性.实际上,你最终得到这样的东西:

4000051357而不仅仅是4000051.

sca*_*bl3 1

我认为这看起来很扎实。每个区域都保持一致性,如果您使用 XDCR,则不会发生冲突。INCR 在集群中是原子的,因此不会有任何问题。您实际上不需要其中包含机器代码部分。如果一个区域内的所有应用服务器都连接到同一个集群,则中缀其中的 00001 部分是无关紧要的。如果这对您出于其他原因(某种分析)有用,那么无论如何,但这不是必要的。

所以它可以简单地是 '4' 。1'(使用您的示例)

你能举个例子说明你需要什么样的“排序”吗?

第一:添加熵的一个缺点(我不确定为什么你需要它)是你不能轻松地迭代 ID 集合。

例如:如果您的 ID 为 1-100,您可以通过 Counter 键上的简单 GET 查询知道,您可以按组分配任务,此任务需要 1-10,接下来的 11-20 等等,以及工人可以并行执行。如果添加熵,则需要使用 Map/Reduce 视图来下拉集合,因此您将失去键值模式的好处。

其次:由于您关心可读性,因此添加文档/对象类型标识符也很有价值,这可以在 Map/Reduce 视图中使用(或者您可以使用 json 键来标识它)。

例如: 'u:' 。‘4’。‘1’

如果您在外部引用 ID,您可能需要以其他方式进行模糊处理。如果您需要一个示例,请告诉我,我可以在我的答案中附加您可以做的事情。

@scalabl3