阅读微服务架构中的模型

Read Model in Microservice Architecture

我对微服务架构中的事件溯源有疑问。

假设每个服务都将自己的事件存储在自己的事件存储中,如果投影需要来自多个服务的数据,我该如何重建读取模型?

例如,我们有 UserService 和 InvoiceService。 在发票服务模型中,我只使用用户 ID,但在读取模型中,我还需要用户名以便于查询。

感谢我现在有这些选择:

  1. 还将用户名存储在发票服务中。不太好,我想因为我的真实来源应该仍然是用户服务。
  2. 创建一个(rest?)api 以在读取模型重建的情况下从用户服务中获取用户名。

我错过了什么吗?有人知道更简单的解决方案吗?

用户可以拥有多个发票,并且使用唯一的用户名从事件源重播/重建模型并不理想(或者至少根据我的理解)。我比较喜欢的路线是有a co-relation identifier。顾名思义,它将帮助您在作为给定业务 task/action 的一部分发生的服务 calls/event 采购记录之间建立相互关系。在重新构建模型时(无论是在仪表板中显示还是在逻辑中显示以执行 model/action 重放),有一些相互关联的东西很重要。通过快速搜索,我找到了 a talk about 个关联 ID。请继续阅读更多相关信息,看看这种方法是否能解决您的业务问题。

Suppose that every service stores its own events in a own eventstore, how can i rebuild a read model if the projection needs data from more than one service?

我想你错过了 eventstore 的概念。服务不应该有自己的事件存储。想象一下,您正在从您的服务发布一个事件,而其他一些服务将不得不订阅您的事件流。您的 eventstore 是所有服务的唯一真实来源。

这样,如果您需要从多个流创建投影,那么您就可以这样做。请查看 this blog post.

现在,如果您不想在 eventstore 端构建投影怎么办。假设,您有一个新的要求来显示包含发票数量、总账单等的用户报告。那么我会执行以下操作 -

  1. 订阅以监听来自 UserService 的 UserCreated、UserBasicInfoUpdated 事件(新订阅)

  2. 订阅以监听来自 InvoiceService 的 InvoiceGenerated 事件(新订阅)

  3. 构建新的读取模型

  4. 然后将之前的订阅(如果有)合并到新的订阅中。这个很重要。因为您不应该对同一事件有多个订阅者。

我同意选项 1 是不明智的。域模型(CQRS 中的更新模型,而不是读取模型)应该只有指向其他域的主键指针,不支持来自这些域的数据。

选项 2 更好,但仍不尽如人意。在使用事件溯源时,我不喜欢 API 域之间的调用,因为它可能导致一个域失败或由于第二个域的困难而显得缓慢。在您的示例中,发票域在用户域上调用 API 以获取用于读取模型重建的用户名,这意味着如果用户域关闭,发票域无法完成其重建——发票域无故失败自己的。

考虑在 Invoice 域中缓存用户信息的选项 3。为 Invoice 域中的适当用户事件创建侦听器,并在那里缓存必要的用户数据——在本例中只是主键和用户名,但如果需要,您可以稍后添加更多字段。然后使用此缓存重建您的发票读取模型,因此不依赖于用户域。

只是一个澄清说明,以确保我们都在同一页上,并且对于那些不熟悉 CQRS 的读者。发票读取模型应该包含用户标识和用户名,但领域模型应该只有用户标识。阅读模型到处都有重复的信息,并不打算成为第三范式;它们应该非常快并且包含将显示在屏幕上的所有信息。