不使用关系数据库的全局序列号生成器

Global sequential number generator without using a relational database

我有申请。假设这是一个发票服务。每次用户创建发票时,我都需要分配下一个序号(即:ISequentialNumberGeneratorRepository.Next(); 因此,尽管我的应用程序有多个实例 运行,但本质上发票编号必须是唯一的(水平可扩展性可能在未来)。

换句话说,我需要一个全局序号生成器。

传统上,这个问题是通过使用关系数据库解决的,例如 SQL 服务器、PostgreSQL、MySQL 等,因为这些系统具有生成顺序唯一 ID 的能力插入记录并将生成的 ID 作为同一原子操作的一部分返回,因此它们非常适合集中式序列号生成器。

但是我没有关系数据库而且我也不需要,所以仅仅为了这个微小的功能而不得不使用它有点残酷。

不过,我有一个 EventStore 可用 (EventStore.org),但我无法确定它是否具有序列号生成功能。

所以我的问题是:是否有任何可用的产品可以用来生成唯一的序列号,以便我可以实现我的 Next(); 存储库的方法,并且无论有多少,它都能很好地工作我拥有的客户发票申请实例?

注意:或者,如果有人能想出一种为此目的使用 EventStore 的方法,或者他们是如何在 DDD/CQRS/ES 环境中实现这一点的,那就太好了。

恕我直言,您的要求有点缺陷,因为您的需求存在冲突。

您想要一个唯一的 ID。通常的解决方案使用:

  • 引导。可以集中或本地生成。真的很容易实施。对人类来说有点难 reader,但是 YMMV。但是你想要增量密钥。
  • 集中分配密钥:您需要一个交易系统。但是您想做 CQRS,并使用 Event Store。在我看来,拥有一个单独的事务系统只是为了拥有一个 IDENTITY_COLUMN 或一个 SEQUENCE 在很大程度上错过了做 CQRS 的意义。
  • 使用 HiLo 生成方法。也就是说:每个客户都会获得一个独特的种子(比如第一个客户 10 亿,第二个客户 20 亿,等等)。因此每个客户端都可以在本地生成一个序列。这个序列是分布式的,使用序号,所以没有并发问题,但是没有对请求进行全局排序,你必须保证没有两个客户端得到相同的Hi值(相对容易的任务)。
  • 使用Event Store分配的id。我不知道产品,但发送到队列的每个事件都有一个唯一的 ID。但是(据我了解)您需要在发送事件之前提供 id。

您通常可以将这些解决方案(尤其是 Hilo 算法)与时间戳(例如来自 Unix Epoch 的秒数,或类似的东西)混合搭配,以产生(弱的、无法保证的)可排序性。但通常我会避免这种情况,因为如果你在多个站点生成 id,就会引入时钟不同步的风险,以及通常其他未解决(或无法解决)的问题。

可能我遗漏了一些东西,但这是我脑海中的一些东西。

所以,据我所知,你陷入了困境。我会非常努力地让自己处于以前的情况之一。

您没有说明您想要此功能的原因(或提供任何代码)。我假设术语顺序应该被视为单调递增(排序而不是循环)。

我倾向于同意 A.Chiesa,我会在列表中添加时间戳,尽管此处不适用。

由于您的 post 没有说明数据是如何被使用的,我打算有两个解决方案,如果可能的话,第二个优先于第一个;对于所有后来的访问者,请改用数据库解决方案。

保证跨水平扩展应用程序的数字顺序而不聚合的唯一方法是利用中央服务器分配数字(使用 REST 或 RPC 或自定义网络代码;更不用说 SQL 服务器,作为旁注)。由于并发性,应用程序必须等待轮到下一个数字,包括网络使用和延迟,这种延迟限制了应用程序的可扩展性,并提供单点故障。这些风险可以通过创建中央服务器的多个实例和多个应用程序池来最小化(您将失去全局排序能力)。

作为替代方案,我会推荐 HI/LO 分配方法,结合批量聚合。每个实例都有四个?每个实例以递增数字为前缀的数字标识符。在中央(或多个,用于冗余)服务器上安排聚合任务以获取数据并在聚合期间分配顺序唯一 ID。此过程对数据进行本地化(直到拾取,可以将其安排为 (100, 500, 1000)?如果需要一致性,则为毫秒间隔;如果不需要,则为几分钟或更长时间),并提供几乎完美的水平缩放,但缺点是增加了垂直聚合服务器的扩展要求。

分布式计算是处理、内存和通信开销之间的平衡行为。您的 computing/memory/network 容量边界所在的位置无法根据您的 post.

确定

没有一个正确答案。我已经为您提供了两种可能性,但没有手头任务的具体要求,我不能再进一步了。

意见很奇怪

so it's a bit brutal having to use one just for this tiny functionality.

如今,即使在手机中,SQLite 也被用作关系数据库。它很简单,内存占用小,并且对所有流行的编程语言都有绑定。 20 年前,数据库消耗了大量资源——如今,您可以找到适用于所有任务的数据库引擎。此外,如果您需要微型密钥对存储,您可以使用 BerkeleyDB。