这是一篇不错的文章,它描述了它是什么ES
以及如何处理它。
那里一切都很好,但有一张照片让我很困扰。这里是
我知道在分布式基于事件的系统中,我们只能实现最终的一致性。无论如何......我们如何确保我们不会预订比可用座位更多的座位?如果有许多并发请求,这尤其是一个问题。
可能会发生 n 个聚合填充了相同数量的预留座位,并且所有这些聚合实例都允许预留。
这是一篇不错的文章,它描述了它是什么ES
以及如何处理它。
那里一切都很好,但有一张照片让我很困扰。这里是
我知道在分布式基于事件的系统中,我们只能实现最终的一致性。无论如何......我们如何确保我们不会预订比可用座位更多的座位?如果有许多并发请求,这尤其是一个问题。
可能会发生 n 个聚合填充了相同数量的预留座位,并且所有这些聚合实例都允许预留。
我知道在分发基于事件的系统中,我们只能实现最终的一致性,无论如何......如何不允许预订比我们拥有的更多的座位?特别是在许多并发请求方面?
在记录簿确认写入成功之前,所有事件对于运行它们的命令都是私有的。所以我们根本不分享事件,也不向调用者报告,不知道我们版本的“接下来发生的事情”已被记录簿接受。
事件的写入类似于聚合历史中尾指针的比较和交换。如果在我们运行时另一个命令更改了尾指针,我们的交换失败,我们必须减轻/重试/失败。
在实践中,这通常通过让记录簿的写入命令包括写入的预期位置来实现。(例如: GES 中的 ES-ExpectedVersion)。
如果预期位置在错误的位置,则记录簿将拒绝写入。将位置视为 RDBMS 中表中的唯一键,您的想法是正确的。
这实际上意味着对事件流的写入实际上是一致的——记录簿仅在您写入的位置正确时才允许写入,这意味着自您复制历史以来该位置没有改变加载已写入。
命令通常直接从记录簿中读取事件流,而不是最终一致的读取模型。
可能会发生 n-AggregateRoots 将填充相同数量的预留席位,这意味着在预留方法中进行验证将无济于事。然后 n-AggregateRoots 将发出成功预订的事件。
每一点状态都需要由单个聚合根来监督。您可以运行该根的 n 个不同副本,所有副本都竞争写入相同的历史记录,但比较和交换操作将只允许一个获胜者,这确保了“该”聚合具有单个内部一致的历史记录。
将有几种方法来处理这种情况。
首先,事件流将当前版本作为添加的最后一个事件的版本。这意味着,如果事件流不是加载时的版本,您将不会或不应该能够持久化事件流。由于第一次写入会导致事件流的版本增加,因此不允许第二次写入。由于事件本身并没有发出,而是事件源的结果,我们不会在您的示例中具有竞争条件的类型。
好吧,如果您的命令在队列后面处理,则应重试任何失败。如果无法处理请求,您将通过让用户知道他们应该尝试其他方法来进入正常的“对不起,Dave。我担心我做不到”场景。
另一种选择是通过对某个表行发出更新来开始处理,以序列化对聚合的任何调用。可能不是最优雅的,但它确实会导致系统范围的处理阻塞。
我想,在很大程度上,在事务处理方面,人们不能真正信任读取存储。
希望有帮助:)