【问题标题】:Event Consumers in Event Sourcing and duplicate code事件溯源中的事件消费者和重复代码
【发布时间】:2018-06-19 06:32:21
【问题描述】:

我对事件溯源还很陌生,我们有一个域,我们考虑在其上应用事件溯源。

我们有一个应用程序将域事件存储到Oracle DB 和事件的消费者将使用它们来生成读取模型(所有读取模型都将在内存中生成),这些消费者将主要使用轮询模型来获取事件。

这意味着他们将收到一个请求,并根据该请求消费一个事件流并生成他们的读取模型,然后将其返回给调用者。

例如

Event Generation API --> 为类型 A 的聚合生成事件并将它们存储在 Oracle DB 中。

Consumer 1 --> 获取特定类型 A 聚合的请求,然后获取事件并重放它们以准备其读取模型。

Consumer 2 --> 做同样的事情,但呈现不同的读取模型

我们为什么要使用 ES

  1. 我们需要提供每次更改的数据历史表示形式以及该更改时的聚合状态。
  2. 我们需要能够在每个事件的任何时间点获取聚合的快照,例如,在更改名称时,我们需要该名称更改事件时间的聚合状态
  3. 我们需要表示时间点之间聚合状态的差异

但是所有这些要求都需要以轮询的方式完成,这意味着消费者将在某个时间点请求视图(可能是最新的或以前的)

问题 1

既然consumer 1consumer 2 都将执行基本相同的逻辑来重放事件,那么重放事件的代码应该在哪里呢?我们会实现一个通用的库代码吗?这是否意味着我们将在消费者之间拥有重复的重放代码?

我担心当我们更新一个事件架构时,我们需要更新多个消费者

问题 2

这是一个很好的事件溯源案例吗?

【问题讨论】:

    标签: events architecture microservices cqrs event-sourcing


    【解决方案1】:

    这意味着他们将收到一个请求,并根据该请求消费一个事件流并生成他们的读取模型,然后将其返回给调用者。

    这是一种奇怪的 Read 模型,至少对我来说是这样。它似乎不是很快,速度是读取模型的优势之一。

    一般来说,Read 模型尽可能早地在后台处理事件(即在它们发出后的毫秒内);结果保存在一个快速的数据库中(在磁盘或内存上),应用了所有索引,因此当请求到来时,响应很快。

    1. 我们需要为每次更改提供数据的历史表示形式以及该更改时的聚合状态。

    2. 我们需要能够在每个事件的任何时间点获取聚合的快照,例如,更改名称,然后我们需要该名称更改事件的状态

      李>

    Aggregate 的状态应该是隐藏的、私有的——Aggregate 需要高级别的封装。也许您需要对在此之前生成的事件进行解释:这是读取模型的职责。聚合使用状态来决定是否以及在下一个命令中将生成哪些事件。

    因此,我建议您设计一个读取模型来完全做到这一点:它为每个聚合维护另一个状态,在一个平面(非事件源)持久性中。

    1. 我们需要表示时间点之间聚合状态的差异

    同样,这应该由读取模型完成。

    既然消费者 1 和消费者 2 都将执行基本相同的逻辑来重放事件,那么重放事件的代码应该在哪里呢?我们会实现一个通用的库代码吗?这是否意味着我们将在消费者之间拥有重复的重放代码?

    但后来你说:Consumer 2 --> does exactly the same thing but presents a different read model。这意味着他们基本上不会做同样的事情。如果您指的是从事件存储中获取事件并提供给消费者的代码,那么是的,您可以将它放在一个公共库中。

    我担心我们在更新事件架构时需要更新多个消费者

    这是一个问题,但有multiple solutions

    这是一个很好的事件溯源案例吗?

    似乎是的,它可能是事件溯源的一个案例。

    【讨论】:

    • 好吧,问题是在我们收到请求之前我们无法真正生成读取模型,因为它们可以是随机的,并且可以在任何时间点请求数据。您能否详细说明“聚合的状态应该是隐藏的、私有的 - 聚合需要高级别的封装”。我的意思是域状态或我们的数据在那个时间点的外观,消费者将呈现给它的请求调用者
    • 我还想提一下,我们会定期对传统 RDBMS 表模式中的数据进行快照,这些事件消费者会提供涉及历史事件的数据的不同表示形式
    • @engma 在 CQRS 中,根据定义,聚合(写入/命令模型)不得被查询。您(客户端代码、应用程序服务等)无法知道聚合中的内容,它的状态是私有的。为此,您拥有 Read 模型;您构建它们是为了构建另一个适合查询需求的状态。在某些情况下,读取状态看起来很像写入/聚合的状态:没关系,它们必须以不同的方式存储在不同的持久性中。
    • 是的,所以我的事件消费者只会获取事件并使用它们来构建他们需要的表示或他们需要的数据读取模型。主要区别在于我们使用投票模型,因此事件流不会有订阅者,他们将更像消费者(至少目前我们没有发布/订阅计划)
    • @engma 是的。接收事件的方法无所谓,在pub/sub中也是一样的。轮询提供了更好的弹性,但这是另一个话题。您可以在请求到来时构建读取模型,它是允许的,但它并不快。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-06
    • 2021-06-24
    • 2020-05-27
    • 1970-01-01
    • 2021-07-25
    • 2018-09-23
    • 2016-04-28
    相关资源
    最近更新 更多