识别微服务边界
微服务的大小合适? 你经常听到一些影响的东西,“不是太大,不是太小”-虽然这当然是正确的,但它在实践中并不十分有用。 但是,如果你从精心设计的域模型开始,那么对微服务来说要容易得多。
本文使用无人机交付服务作为正在运行的示例。 可以 在此处阅读有关方案的详细信息和相应的参考实现。
从域模型到微服务
在 上一篇文章中,我们定义了无人机交付应用程序的一组有限上下文。 然后,我们更仔细地查看了其中一个边界上下文,即“传送”边界上下文,并为该边界上下文标识了一组实体、聚合和域服务。
现在,我们已准备好从域模型到应用程序设计。 下面是一种方法,可用于从域模型派生微服务。
从边界上下文开始。 一般情况下,微服务中的功能不应跨越多个边界上下文。 根据定义,边界上下文标记特定域模型的边界。 如果发现微服务将不同的域模型混合在一起,则表明可能需要返回并优化域分析。
接下来,查看域模型中的聚合。 聚合通常是微服务的良好候选项。 设计良好的聚合展示了设计良好的微服务的许多特征,例如:
- 聚合派生自业务要求,而不是数据访问或消息传送等技术问题。
- 聚合应具有较高的功能凝聚力。
- 聚合是持久性的边界。
- 聚合应松散耦合。
域服务也是微服务的良好候选项。 域服务是跨多个聚合的无状态作。 典型示例是涉及多个微服务的工作流。 我们将在无人机交付应用程序中看到一个示例。
最后,考虑非功能性要求。 查看团队大小、数据类型、技术、可伸缩性要求、可用性要求和安全要求等因素。 这些因素可能导致将微服务进一步分解为两个或更多较小的服务,或者执行相反作,并将多个微服务合并为一个。
在应用程序中标识微服务后,根据以下条件验证设计:
- 每个服务都有一个责任。
- 服务之间没有聊天调用。 如果将功能拆分为两个服务会导致它们过于闲聊,则可能是这些函数属于同一服务的症状。
- 每个服务都足够小,它可由独立工作的小型团队构建。
- 没有任何依赖关系需要两个或多个服务部署在锁定步骤中。 始终可以部署服务,而无需重新部署任何其他服务。
- 服务没有紧密耦合,可以独立发展。
- 服务边界不会造成数据一致性或完整性问题。 有时,通过将功能放入单个微服务来维护数据一致性非常重要。 也就是说,考虑你是否真的需要强烈的一致性。 有一些策略可以解决分布式系统中的最终一致性问题,分解服务的好处往往超过了管理最终一致性的挑战。
最重要的是,必须务实,并记住域驱动设计是一个迭代过程。 毫无疑问,请从更粗粒度的微服务开始。 将微服务拆分为两个较小的服务比在多个现有微服务中重构功能更容易。
示例:为无人机交付应用程序定义微服务
回想一下,开发团队已确定四个聚合:交付、包裹、无人机和帐户,以及两个域服务、计划程序和主管。
交付和包是微服务的明显候选项。 计划程序和监督程序协调其他微服务执行的活动,因此,将这些域服务实现为微服务是有意义的。
无人机和帐户很有趣,因为它们属于其他边界上下文。 一个选项是计划程序直接调用无人机和帐户边界上下文。 另一种方法是在传送边界上下文中创建无人机和帐户微服务。 这些微服务通过公开更适用于 Shipping 上下文的 API 或数据架构,在边界上下文之间进行调解。
无人机和帐户边界上下文的详细信息超出了本指南的范围,因此我们在参考实现中为它们创建了模拟服务。 但在这种情况下,需要考虑以下一些因素:
直接调用其他边界上下文的网络开销是什么?
另一个边界上下文的数据架构是否适合此上下文,或者最好有一个针对此边界上下文定制的架构?
另一个边界上下文是否为旧系统? 如果是这样,可以创建一个充当 反腐层 的服务,以便在旧系统与新式应用程序之间进行转换。
什么是团队结构? 与负责其他边界上下文的团队沟通是否很容易? 否则,创建在两个上下文之间调解的服务有助于降低跨团队通信的成本。
到目前为止,我们还没有考虑任何非功能性要求。 在考虑应用程序的吞吐量要求时,开发团队决定创建一个单独的引入微服务,负责引入客户端请求。 此微服务通过将传入请求放入缓冲区进行处理来实现 负载调配 。 计划程序将从缓冲区读取请求并执行工作流。
非功能要求导致团队创建一项附加服务。 到目前为止,所有服务都是关于实时计划和交付包的过程。 但是,系统还需要在长期存储中存储每个交付的历史记录,以便进行分析。 团队考虑将此作为交付服务的责任。 但是,对于历史分析与正在进行的作,数据存储要求大相径庭(请参阅 数据注意事项)。 因此,团队决定创建单独的传递历史记录服务,该服务将侦听传递服务中的 DeliveryTracking 事件,并将事件写入长期存储。
下图显示了此时的设计:
下载此体系结构的 Visio 文件。
后续步骤
此时,应清楚地了解设计中每个微服务的用途和功能。 现在可以构建系统。