【问题标题】:Reporting in ES/DDD MicroservicesES/DDD 微服务中的报告
【发布时间】:2017-04-25 03:11:35
【问题描述】:

我刚开始使用 ES/DDD,我有一个问题,应该如何在此架构中进行报告。让我们举一个典型的例子,你有一个客户聚合、订单聚合和产品聚合都是独立的。

现在,如果我想对所有 3 个聚合和/或服务运行查询,但这些数据分别位于单独的数据库中,可能一个是 SQL,一个是 MongoDB,还有一个是其他的。应该如何设计或能够运行需要跨这些聚合连接的查询?

【问题讨论】:

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


    【解决方案1】:

    您应该将Reporting 设计为一个简单的read-model/projection,可以在它自己的bounded context (BC) 中,只听从相关的events其他有界上下文(Customer BCOrdering BCInventory BC)并使用完整的数据非规范化构建所需的报告(即在查询时您不需要查询原始来源)。

    由于事件,您不需要任何 joins,因为您可以维护一个附加到 Reporting read-model 的私​​有本地状态,您可以在其中存储临时外部模型并根据需要查询这些临时读取模型,从而避免外部附加向其他BCs查询。

    在这种情况下不需要防损坏层,因为Reporting BC 中不涉及写入模型。

    事情就这么简单,因为您已经有了一个事件驱动的架构(您使用Event sourcing)。

    更新:

    这种特殊的解决方案在创建您事先没有想到的新报告时非常方便。每次您处理新报告时,您只需创建一个新的读取模型(就像您编写它的源代码一样),然后您就可以重放所有相关事件。读取模型没有副作用,您可以随时随地重播所有事件(从时间开始)。

    读取模型重建在两种情况下完成:

    1. 您创建了一个新的读取模型
    2. 您通过侦听新事件来修改现有的,或者算法与初始版本相差太大

    您可以在这里阅读更多内容:

    1. DDD/CQRS specialized forum - Grey Young is there!
    2. Event sourcing applied – the read model
    3. Writing an Event-Sourced CQRS Read Model
    4. A post in first group describing Read Model rebuilding

    或者您可以使用以下文本搜索此内容:event sourcing projection rebuilding

    【讨论】:

    • 这是否意味着报告 BC 将包含来自其他有界上下文的所有事件,因为这似乎是能够跨所有域对象进行查询的唯一方法,或者至少作为事件从每个其他 BC 中提取相关信息并在报告 BC 中建立实体。此外,这意味着所有报告都必须预先计划好,如何添加需要一些以前未从到达事件中提取的数据的额外报告?那么您是否必须从头开始重播所有事件并提取
    • 需要数据,以便您提取新报告?同样,这似乎非常复杂,从必须聚合多个事件并从中创建一个记录,到如果稍后需要额外的数据元素来报告并需要从原始事件中提取,则必须重播事件。请让我知道我的理解是否正确,或者如果我在左边的领域,谢谢!
    • 我完全理解。这并不复杂,在事件溯源中非常简单。您所描述的称为读取模型重建。每次创建新的读取模型或注册(开始侦听)现有读取模型中的新事件类型时,您都会进行完全重建。重建得到了很好的讨论。
    • “此外,这意味着所有报告都必须预先计划” - 这是有关事件溯源的“最虚假”声明。每次您发明/思考_一个新的读取模型时,您都会编写其源代码,然后通过重播所有有趣的事件来重建其状态。
    • 有大量关于读取模型(投影)的文章。主要思想是您可以随时随地在读取模型中重播所有事件。读取模型没有副作用!
    【解决方案2】:

    领域驱动设计更关心命令方面的东西。您不应尝试查询您的域,因为这会导致痛苦和痛苦。

    每个有界上下文可能有自己的数据存储,并且该数据存储可能是您所说的不同技术。

    对于报告,您将使用报告商店。您如何将数据导入该存储区将需要每个有界上下文发布报告 BC 将获取并用于更新报告存储区的事件,或者您可以使用事件源,报告存储区会将事件投射到相关报告中结构。

    【讨论】:

    • 也许我误解了,但我认为 DDD 中的 CQRS 允许读写?无论如何,这是有道理的,但是大型应用程序基本上必须从多个服务中捕获事件,然后将其聚合到另一个数据存储中并将其用作分析的读取存储是否可行?出于报告目的,这似乎是一种非常繁琐的方法。
    【解决方案3】:

    有解决此问题的已知做法。

    可能有一个报告上下文,正如 Eben 指出的那样,它将监听来自其他上下文的域事件并更新其存储。这当然会导致问题,因为此报告上下文将与它报告的所有服务耦合。有人可能会说这是必要的邪恶,但并非总是如此。

    另一种技术是按需聚合。这不是很复杂,可以在不同的层/级别上完成。如果您的报告在屏幕上(例如,不是通过邮件以 PDF 格式发送),请考虑在 Web API 级别甚至前端级别进行聚合。 这就是众所周知的 UI 组合,Udi Dahan 写过一篇关于此的文章,值得一读:UI Composition Techniques for Correct Service Boundires。此外,Mauro Servienti 最近写了一篇关于此的博文:The secret of better UI composition

    Mauro 提到了我上面提到的两种类型的构图。 API/服务器端组合在他的帖子中称为ViewModel 组合,而前端(JavaScript)组合在客户端组合过程部分提到。这张图说明了服务器端的组合:

    【讨论】:

    • 正如我在其他评论中提到的,它在理论上看起来可行,但非常不可行。在这种情况下,我们将所有内容分解为微服务,这是有道理的,但随后尝试将所有内容汇总起来以报告每个单独的事件或数据片段在这种情况下到达不同的时间点。对于大型应用程序和更大的数据集,这似乎会变得非常痛苦。您在为具有大量报告和分析要求的大型应用程序实施 DDD 和 ES 方面的经验如何?
    • 好吧,如果它本身就是目标,那么报告上下文确实有意义。我不是在谈论微服务,但由于每个有界上下文都有自己的持久性,因此需要一些软数据组合。事件驱动的数据同步是一种非常有效的方法。具体选择始终取决于要求和个人喜好的结合。
    【解决方案4】:

    DDD 战略建模工具说:

    设计两个不同的模型 1. 编写模型(处理命令端) 2. 读取模型(POCO/POJO),无论您如何称呼它们。

    【讨论】:

      猜你喜欢
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      • 2018-08-12
      • 2021-01-01
      • 2021-04-13
      • 1970-01-01
      • 1970-01-01
      • 2020-10-06
      相关资源
      最近更新 更多