EventSourcing竞争条件

时间:2016-11-15 11:26:56

标签: domain-driven-design cqrs event-sourcing event-driven-design

Here是一篇很好的文章,它描述了什么是ES以及如何处理它。

那里的一切都很好,但有一张图片困扰着我。这是

ES example

据我所知,在基于分布式事件的系统中,我们只能实现最终的一致性。无论如何......我们如何确保我们不会预订更多座位?如果有许多并发请求,这尤其是一个问题。

可能会发生n个聚合使用相同数量的预留席位填充,并且所有这些聚合实例都允许预订。

2 个答案:

答案 0 :(得分:2)

有几种方法可以解决这种情况。

首先,事件流将当前版本作为添加的最后一个事件的版本。这意味着,如果事件流不是加载时的版本,则不能或不应该持久保存事件流。由于第一次写入会导致事件流的版本增加,因此不允许第二次写入。由于事件本身并未发出,而是事件来源的结果,因此我们不会在您的示例中使用竞争条件类型。

好吧,如果您的命令在队列后处理,则应重试任何失败。如果无法处理请求,您将进入正常状态"对不起,戴夫。我担心我不能这样做"通过让用户知道他们应该尝试别的东西。

另一种选择是通过对某些表行发出更新来序列化对聚合的任何调用来启动处理。可能不是最优雅但它会导致系统范围内的处理阻塞。

我想,在很大程度上,当涉及到事务处理时,不能真正信任读取存储。

希望有所帮助:)

答案 1 :(得分:0)

  

据我所知,在发布基于事件的系统时,我们只能实现最终的一致性,无论如何...如何不允许预订比我们更多的席位?特别是在许多并发请求方面?

所有事件对于运行它们的命令都是私有的,直到记录簿确认成功写入为止。所以我们根本不分享这些事件,我们不会向调用者报告,而不知道我们的“接下来发生了什么”的版本被记录簿接受了。

事件的写入类似于聚合历史中尾部指针的比较和交换。如果另一个命令在我们运行时更改了尾指针,则我们的交换失败,我们必须缓解/重试/失败。

实际上,这通常通过使记录簿的写入命令包括写入的预期位置来实现。 (示例:GES中的ES-ExpectedVersion)。

如果预期的位置在错误的位置,预计记录簿将拒绝写入。将该位置视为RDBMS中表中的唯一键,并且您有正确的想法。

这实际上意味着对事件流的写入实际一致 - 如果您写入的位置正确,则记录簿仅允许写入,这意味着该位置没有自从您加载的历史记录副本被写入以来,我没有改变。

命令通常直接从记录簿中读取事件流,而不是最终一致的读取模型。

  

可能会发生n-AggregateRoots将填充相同数量的预留席位,这意味着在预留方法中进行验证将无济于事。然后n-AggregateRoots将发出成功预约的事件。

每个状态都需要由单个聚合根监督。您可以运行该根的n个不同副本,所有副本都会竞争写入相同的历史记录,但比较和交换操作只允许一个获胜者,这可确保“该”聚合具有单个内部一致的历史记录。