DDD,CQRS / ES& MicroServices是否应该对微服务的观点或聚合做出决定?

时间:2018-05-20 13:07:10

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

因此,我将通过使用一个例子来解释这个问题,因为它会使一切变得更加具体,并且希望能够减少歧义。

架构非常简单

1 MicroService< => 1 Aggregate< =>交易边界

每个微服务都将使用CQRS / ES设计模式,这意味着

  • 每个微服务都有自己的聚合映射现实世界问题的领域
  • 聚合的状态将从事件存储重建
  • 每个事件都将表示聚合中的状态更改,并将通过消息代理传输给任何对此更改感兴趣的服务
  • 每个微服务都将在自己的域内进行交易
  • 每个微服务最终将与其他域一致
  • 每个微服务都将根据其他微服务发出的事件构建自己的视图模型

所以这个例子可以说我们有一个银行系统

  • current-account微服务负责映射客户经常账户...提款,存款
  • rewards微服务将负责银行提供的任何奖励的库存和库存
  • air-miles微服务将负责监控来自current-account的所有交易,并通过我们的奖励微服务奖励客户奖励

所以问题是这个air-miles微服务是否应该根据自己的视图模型做出决策,该模型是从current-account的事件中更新的,同样地,选择应该给出的奖励对客户?

对本地视图模型做出决策的缺点;

  • 复制关于如何维护这些视图的域逻辑
  • 视图中的错误可能会传播错误的奖励
  • 在损坏的视图模型上的状态更改(也就是发出的事件)可能会对正在自行决定这些事件的其他服务产生影响

对本地视图模型做出决策的好处;

  • 系统不需要经常查询拥有域的微服务
  • 系统应该更快,资源消耗更少

    或者它是否应该使用来自服务的事件来触发对拥有域的聚合的查询,这样做我们接受视图模型可能会损坏的事实但是最终决策应始终与拥有域的聚合一起查阅

请注意,上述问题不仅仅是我对架构的理解,而且这篇文章的目的是就如何在微服务环境中有效地使用这种架构来保持每个服务分离但避免级联腐败有不同的看法场景,服务之间没有太多的喋喋不休。

2 个答案:

答案 0 :(得分:3)

  

问题是这个吗?空中里程微服务是否应根据自己的视图模型做出决策,该模型正在从来自当前账户的事件中更新,同样地,选择应该向客户提供哪些奖励?

是。实际上,您应该修改您的架构,甚至创建更多的微服务。我的意思是,作为一个事件驱动的架构(也是一个事件来源的架构),您的微服务有两个职责:它们需要保留两个不同的模型:写模型和读模型。

因此,对于每个Aggregate应该是一个只保留写模型的微服务,也就是说,它只处理命令,而不构建一个读模型。

然后,对于每个读/用用例,您应该有一个构建完美读取模型的微服务。如果您需要保持Aggregate微服务干净(如您所愿),则需要这样做,因为通常,读取模型需要来自多个聚合类型/有界上下文的数据。读取模型可能跨越有界上下文边界,聚合可能不会。所以你看,如果你需要完全尊重DDD,你真的没有选择。

有些人说域名事件应该被隐藏,只有本地的微型服务。我不同意。在事件驱动的体系结构中,域事件是一等公民,允许它们到达其他微服务。这使得其他微服务有机会建立自己对系统状态的解释。否则,发射微服务将具有不可能的附加责任/任务,即建立一个必须匹配所有微服务所需的每个可能需求的状态(!);也许微服务可能想要查找已删除的远程实体的title,如果发射微服务仅保留未删除的列表实体?你可能会说:但是它将保留所有实体,删除与否。但也许某人需要删除实体的日期;你可能会说:但是我还保留deletedDate。你明白你做了什么?你违反了开放/封闭原则。每次创建微服务时,都需要修改发射微服务。

还有微服务的弹性。在Art of scalability中,作者谈到了泳道。它们是将系统组件分成故障通道的策略。车道故障不会传播到其他车道。我们的微服务是车道。车道中的组件不允许访问其他车道的任何组件。一个微服务不应该让其他人失望。这不是速度/优化的问题,而是弹性的问题。域事件是保持两个远程系统同步的完美模式。他们还强调数据最终是一致的;事件以有限的速度传播(从纳秒到偶数天)。当系统设计时考虑到这一点,那么没有其他微服务可以降低它。

是的,会有一些代码重复。是的,虽然我说你没有选择,但你有。为了以较低的弹性为代价减少代码重复,您可以使用一些Canonical读取模型来构建普通平面状态,而其他微服务可以查询。这在大多数情况下是危险的,因为它打破了泳道的概念。如果Canonical微服务发生故障,请关闭所有相关的微服务。 Canonical微服务最适合类似CRUD的有界环境。

但是,有些情况下您可能会遇到一些您不想公开的内部事件。换句话说,您不需要发布所有域事件。

答案 1 :(得分:1)

  

所以问题是这应该是空中里程微服务根据自己的视图模型做出决策,该模型正在从来自当前账户的事件中更新,同样地,选择应该给予客户的奖励?

每个消费者使用由生产者计算的表示的本地副本。

因此,如果air-miles需要来自current-account的信息,则应该查看由current-account服务计算的视图的本地副本。

关键的想法是:微服务应该彼此隔离;你应该能够重新设计和部署一个而不会影响其他人。

所以尝试这个思想实验 - 假设我们有这三个微服务,但都保存当前状态的快照,而不是事件。一切正常,然后想象current-account维护者发现事件源实现将更好地为业务服务。

current-account的更改是否需要air-miles服务中的匹配更改?如果是这样,我们真的可以声称这些服务是彼此隔离的吗?

  

对本地视图模型做出决策的好处

我并不特别喜欢这些"优点&#34 ;;首先,它们由性能轴支配(请回想一下,性能优化的第二规则是"还没有")。第二,他们假设正确绘制了服务边界;也许绩效问题证明责任分离需要审查。