InfoQ如何基于 DDD 构建微服务?( 四 )


重新定义的聚合列表 。 这些可能会成为新的微服务
需要在这些微服务之间流动的领域事件
其他应用程序或用户直接调用的命令
下面是我们在一次事件风暴研讨会结束时产生的一个示例样板 。 对于团队来说 , 就正确的聚合和界限上下文达成一致是一次很棒的协作活动 。 此外 , 团队在本次会议结束时还对领域、统一语言和精确的服务边界有着共同的理解 。

InfoQ如何基于 DDD 构建微服务?
本文插图
图 6:事件风暴板
微服务之间的通信
快速回顾一下 , 一个单体应用在单个流程边界内拥有多个聚合 。 因此 , 可以在这个边界内管理各个聚合的一致性 。 例如 , 如果客户下了订单 , 我们可以减少商品库存 , 并向客户发送电子邮件 , 所有这些都在一个事务中完成 。 所有操作要么都成功 , 要么都会失败 。 但是 , 当我们分解了单体并将聚合分散到不同的上下文中时 , 我们将拥有数十个甚至数百个微服务 。 但目前为止 , 存在于单体应用单一边界内的流程 , 现在被分散到了多个分布式系统中 。 要在所有这些分布式系统中实现事务的完整性和一致性是非常困难的 , 而且要以系统的可用性为代价 。
微服务也是分布式系统 。 因此 , CAP 定理也适用于它们:“一个分布式系统只能提供三个所需特性中的两个:一致性、可用性和分区容错(CAP 中的‘C’——Consistency、‘A’——Availability 和 ‘P’——Partition Tolerance) 。 ”在现实世界的系统中 , 分区容错是不可协商的——网络是不可靠的、虚拟机可以宕机、区域之间的延迟可能会变得更糟等等 。
因此 , 我们可以选择“可用性”或“一致性” 。 现在 , 我们知道 , 在任何现代应用程序中 , 牺牲“可用性”也不是一个好主意 。
InfoQ如何基于 DDD 构建微服务?
本文插图
图 7:CAP 定理
围绕最终一致性设计应用程序
如果我们想要跨多个分布式系统构建事务 , 那么我们将再次陷入单体应用的困境 。 但这一次它会是最糟糕的一种单体:一个分散的单体应用 。 如果这些系统中的任何一个变得不可用 , 则整个流程不可用 , 通常会导致极差的客户体验、承诺的失败等等 。 此外 , 对一个服务的变更通常会导致另一个服务的变更 , 从而引起复杂和昂贵的部署 。 因此 , 我们最好根据自己的用例来设计应用程序 , 容忍稍微的不一致 , 以提高可用性 。 对于上面的例子 , 我们可以使所有流程异步 , 从而达到最终的一致性 。 我们可以独立于其他流程 , 异步发送电子邮件;如果已经承诺的商品以后在仓库中不可用 , 那么该商品可能需要补货 , 或者我们可以停止接受超出某个阈值的该商品的订单 。
有时 , 我们可能会遇到这样的场景:可能需要跨越不同流程边界的两个聚合的强 ACID 式的事务 。 这是一个重新审视这些聚合并将它们组合成一个聚合的极好迹象 。 开始在不同流程边界中分解这些聚合之前 , 事件风暴和上下文映射将有助于我们及早识别这些依赖关系 。 将两个微服务合并为一个的成本很高 , 这是我们应该努力避免的 。
支持事件驱动的架构
微服务可以将发生在其聚合上的基本更改发出来 , 这些称为领域事件(Domain Event) , 并且任何对这些更改感兴趣的服务都可以监听这些事件并在其领域内执行相应的操作 。 这种方法避免了任何行为上的耦合(一个领域无需规定其他领域应该做什么)以及时间上的耦合(一个流程的成功完成不依赖于所有系统同时可用) 。 当然 , 这将意味着系统最终是一致的 。
InfoQ如何基于 DDD 构建微服务?
本文插图