在 ES/DDD 微服务中报告

Reporting in ES/DDD Microservices

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

现在,如果我想 运行 查询所有 3 个聚合 and/or 服务,但每个数据都在一个单独的数据库中,也许一个是 SQL,一个是MongoDB,还有一件事。人们应该如何设计或能够 运行 需要跨这些聚合进行联接的查询?

领域驱动设计更关注事物的命令方面。您不应尝试查询您的域,因为这会导致痛苦和折磨。

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

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

有已知的做法可以解决这个问题。

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

另一种技术是按需聚合。这不是很复杂,可以在不同的 layers/levels 上完成。如果您的报告显示在屏幕上(例如,不是通过邮件以 PDF 格式发送),请考虑在网络 API 级别甚至前端级别进行聚合。 这是众所周知的 UI 组合,Udi Dahan 写了一篇关于此的文章,值得一读:UI Composition Techniques for Correct Service Boundires. Also, Mauro Servienti has wrote a blog post about this recently: The secret of better UI composition.

Mauro 提到了我上面提到的两种构图。 API/server-side组合在他的post中称为ViewModel Composition中提到了前端(JavaScript)组合客户端合成过程 部分。服务器端组成如下图所示:

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

由于事件的原因,您不需要任何 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

DDD 战略建模工具说:

设计两个不同的模型 1. 编写模型(处理命令端)2.Read 模型(POCOs/POJOs)无论你怎么称呼它们。