Architecture 微服务体系结构中的读取模型

Architecture 微服务体系结构中的读取模型,architecture,microservices,event-sourcing,Architecture,Microservices,Event Sourcing,我有一个关于微服务架构中的事件源的问题 假设每个服务都在自己的eventstore中存储自己的事件,如果投影需要来自多个服务的数据,我如何重建读取模型 例如,我们有UserService和InvoiceService。 在invoice服务模型中,我只使用用户id,但在read模型中,我还需要用户名以便于查询 感谢您,我现在有以下选择: 还将用户名存储在发票服务中。不太好,我认为,因为我的真实来源仍然应该是用户服务 创建一个(rest?)api,以便在读取模型重建时从用户服务获取用户名 我错过什

我有一个关于微服务架构中的事件源的问题

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

例如,我们有UserService和InvoiceService。 在invoice服务模型中,我只使用用户id,但在read模型中,我还需要用户名以便于查询

感谢您,我现在有以下选择:

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

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

    用户可以有多个发票,而仅使用用户名从事件源重播/重建模型并不理想(至少据我所知)。我更喜欢的方法是使用
    关联标识符
    。顾名思义,它将帮助您在作为给定业务任务/行动一部分发生的服务呼叫/事件来源记录之间建立相互关系。在重新构建模型时(无论是在仪表板中显示还是在执行模型/动作回放的逻辑中显示),有一些相关的东西是很重要的。通过快速搜索,我找到了合作关系id。请继续阅读更多信息,看看这种方法是否能解决您的业务问题

    假设每个服务在自己的eventstore中存储自己的事件, 如果投影需要更多数据,如何重建读取模型 不止一项服务

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

    这样,如果需要从多个流创建投影,则可以这样做。请调查一下

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

  • 从UserService订阅侦听UserCreated、UserBasicInfo更新的事件(新订阅)

  • 订阅从InvoiceService侦听InvoiceGenerated事件(新订阅)

  • 构建新的阅读模型

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


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

    选项2更好,但仍然不太理想。我不喜欢在使用事件源时在域之间调用API,因为它会导致一个域失败,或者由于第二个域的困难而显得缓慢。在您的示例中,让发票域在用户域上调用API以获取读取模型重建的用户名意味着,如果用户域发生故障,发票域将无法完成其重建–发票域不会因为自身的故障而失败

    考虑在Invoice域中缓存用户信息的选项3。在Invoice域中创建相应用户事件的侦听器,并在其中缓存必要的用户数据–在本例中,仅包含主键和用户名,但如果需要,您可以稍后添加更多字段。然后使用此缓存重新生成发票读取模型,因此不依赖于用户域


    只是一个澄清说明,以确保我们都在同一页上,并为那些读者谁是新的CQR。发票读取模型中应包含userid和用户名,但域模型中应仅包含userid。阅读模型到处都有重复的信息,不打算成为第三范式;它们的速度非常快,包含屏幕上显示的所有信息。

    谢谢您的回复!是的,一个用户可以有多个发票,两个用户可以有相同的用户名。这就是我在模型中使用ID的原因。我正在为read模型寻找一个好的解决方案。read模型也应该有用户名,这样我就可以方便地查询每个名为“exa…”的用户的发票。我知道我可以用CQR做到这一点,所以每次数据更改时,服务都会更新物化视图。但是重建呢?非常感谢你的评论!但是,如果我只使用一个ES,这难道不会打破解耦微服务系统的想法吗?如果我采用第二种方法——如何重建我的读取模型?解耦微服务体系结构背后的基本思想是解耦不同上下文的边界,因此在每个服务中单独拥有不同的db是一条经验法则。但是ES以时间序列的方式存储事件,不同的服务需要在不同的场合订阅不同的事件。ES负责向订阅的频道发布事件。对不同的微服务使用不同的ES并不能满足这一要求。按照我上面的方法,您实际上可以重建一个模型。在步骤3中,您可以更新读取模型,而不是创建新的读取模型。类似于这样的“set username=@name where userid=@uid”,最终您公开了您的持久性层,相当于在基于CRUD的持久性策略中公开了(关系)数据库模式。是的,在我看来,选项3似乎是最好的主意。如果我想在invoice服务中重建我的用户缓存,我该怎么做?从用户服务导入带有所有用户名和ID的投影是一个好主意吗?无论如何,缓存表都需要一个“重新同步”过程。命中用户域API的东西(我只是