【问题标题】:In a microservice, is the transactional boundary the bounded context or the aggregate?在微服务中,事务边界是有界上下文还是聚合?
【发布时间】:2019-04-10 13:33:56
【问题描述】:

第一个问题应该是:什么可以帮助我决定我的微服务是否应该包含可能包含多个聚合的整个有界上下文,还是应该只包含一个聚合?

如果微服务包含多个聚合,那么我想到的另一个问题是:微服务应该有多个事务边界(每个聚合一个)还是微服务应该只有一个事务边界(有界上下文)?

也许,这些问题的答案是:视情况而定。但我想有一些理由来做出正确的决定。

我试图实现一个实验性的微服务,它实现了一个由 3 个聚合和每个聚合一个事务边界组成的有界上下文,但我遇到了一些痛点:

  • 微服务本身的最终一致性
  • 以弹性方式在微服务中对聚合和发布领域事件进行原子更新
  • 决定是所有领域事件都应该在外部发布(到其他微服务)还是只发布其中的一部分
  • 决定领域事件是否应以集成事件的形式发布,以保持领域模型的纯度

然后我设想了将微服务拆分为多个微服务的可能性,每个聚合一个:

  • 发布所有领域事件变得更加自然(无需明确区分领域事件和集成事件)
  • 降低了微服务的内部复杂度

我还没有找到一些关于这个主题的文档来指导我做出决策。

编辑:

考虑到有界上下文可以是一组作为合作伙伴一起工作的微服务,并且每个微服务将封装一个且只有一个聚合具有自己的扩展策略,是否有意义?

然后,每个微服务将有一个且只有一个更改原因:聚合。

【问题讨论】:

  • 如果你需要在一个事务中使用多个聚合(甚至属于同一个限界上下文或微服务),那么你就是在破坏 DDD 和微服务哲学。这表明设计错误,不应这样做。

标签: domain-driven-design microservices


【解决方案1】:

当然,答案总是“视情况而定”。但在这种情况下,大多数时候,您会希望微服务包含所有必需的,以实现一组封闭的功能。注意我说的是“功能”,就像在业务功能中一样。 不是技术功能,例如将“人”保存到桌子上,而是业务功能,例如“将资金从一个帐户转移到另一个帐户”、“预留座位”等。

用您的话来说,这意味着包含一个事务边界,并且可能包含多个“聚合”。

所有这一切都是因为可维护性。当您修改给定功能(或修复错误等)时,您会希望将其本地化为单个微服务。 任何需要在微服务之间进行协调的事情通常要困难得多。您必须协调团队、协调部署等,而这正是微服务应该解决的问题。

【讨论】:

  • 当微服务封装有界上下文时,我确实喜欢使用有界上下文作为多个聚合的事务边界的想法。毕竟,如果我的每个聚合都需要不同的扩展策略,那么我想我宁愿将它们分开放在自己的微服务中。
【解决方案2】:

您通常可以(视情况而定)将一个有界上下文映射到一个微服务。

一个微服务可以使用多个聚合。

事务边界是聚合执行的操作。此操作不能被聚合之外的任何东西拒绝/撤消/回滚。如果聚合说“是”,那是因为检查了所有业务规则和不变量。不得不从聚合外部拒绝/撤消/回滚聚合操作是错误设计的味道。

提示:除了完全错误的设计之外,细粒度的操作曾经是许多潜在的“撤消”遭遇的解决方案。当按下支付按钮时,用户没有“支付”。因为如果银行拒绝该操作,您必须撤消已注册的“支付”操作(聚合表示,据它所知,用户可以支付)。用户提出“支付”业务操作,包括以下几个步骤:

“Order a payment”:注册订单并引发 UserOrderedPayment 事件,如果聚合显示“OK”。之后,其他一切都是您系统中的内部事件/操作。

UserOrderedPayment 事件启动收费。如果失败,则引发 UserOrderPaymentRejected 事件并将支付订单标记为拒绝。如果收费没有问题,则注册新的付款并引发 UserPaid 事件。

关于

微服务本身的最终一致性

采用上述细粒度设计; MS 本身没有最终的一致性,因为每一步都处于一致的状态。付款订单可能仍处于待处理状态(但它是有效且一致的状态),好的,只需等待几毫秒并刷新 ;-)。

领域事件的聚合和发布的原子更新 以弹性的方式在微服务中进行

再次;具有上述细粒度设计;事务边界只是一个聚合,因此没有“聚合s的原子更新”。由于不应拒绝域事件(无论是否在同一个 MS 内),它们只会因基础设施故障(网络、持久性等)而失败,因此最好的策略是将失败的事件保留在某处,并在中断结束时引发它们。

决定是否所有领域事件都对外发布 (对其他微服务)或只是其中一些

你应该在这里倒转责任。始终引发域事件并提供订阅该事件的方法。这样,责任就落在了必须订阅所需事件的感兴趣的微服务上。

决定领域事件是否以以下形式发布 集成事件以保持领域模型的纯度

您只需要引发相同的域事件,您的集成代码就可以订阅这些事件并执行集成操作。

【讨论】:

    【解决方案3】:

    假设我们遵循每个 BC 一个微服务的方法,事务边界就是微服务。 BC 的每个应用程序服务方法都是一个事务。 BC 内的聚合定义了一组域对象,这些域对象应该一起更改以保持不变性。对聚合的操作应包装到事务中。所以每个应用服务方法应该只调用一个聚合操作。

    【讨论】:

      猜你喜欢
      • 2015-06-20
      • 1970-01-01
      • 2016-12-15
      • 2018-06-17
      • 2020-09-12
      • 2019-04-18
      • 2014-08-22
      • 2020-03-27
      • 1970-01-01
      相关资源
      最近更新 更多