这个微软官方cqrs系列中讲saga的文章,个人觉得不错,分享给大家。
澄清术语
saga这个术语通常在CQRS中讨论,指的是在边界上下文和聚合之间协调和路由消息的一段代码。然而,出于本指南的目的,我们倾向于使用术语流程管理器(process manager)来指代这种类型的代码。有两个原因:
- 术语saga有一个众所周知的、预先存在的定义,其含义与一般理解的CQRS相关的定义不同。
- 流程管理器能更好地描述这种类型的代码的功能角色。
尽管术语saga经常用在CQRS模式的上下文中,但它有一个预先存在的定义。我们在本指南中选择使用术语流程管理器,以避免与这个预先存在的定义混淆。
关于分布式系统的saga一词最初是在Hector Garcia-Molina和Kenneth Salem的论文“Sagas”中定义的。文章提出了一种称为saga的机制,作为使用分布式事务管理长时间运行的业务流程的替代方案。业务流程通常由多个步骤组成,每个步骤都涉及一个事务,并且可以通过将这些单独的事务分组到一个分布式事务中来实现总体的一致性。但是,在长时间运行的业务流程中,使用分布式事务会影响系统的性能和并发性,因为在分布式事务期间必须持有锁。
小提示:
saga 概念通过确保业务流程的每个步骤中的事务都有一个已定义的补偿事务,从而消除了对分布式事务的需要。 这样,如果业务流程遇到错误情况而无法继续,它可以为已经完成的步骤执行补偿事务。 这将撤消业务流程中迄今为止已完成的工作,并保持系统的一致性。
尽管我们选择使用术语流程管理器,但是sagas仍然可以在某些边界上下文中实现CQRS模式的系统中发挥作用。通常,您希望看到一个流程管理器在一个有界上下文中的聚合之间路由消息,并且您希望看到一个管理跨多个有界上下文中的长时间运行的业务流程。
接下来的部分我们将描述流程管理器这个术语的含义。这是我们在CQRS项目中使用的定义。
小提示:
有一段时间,开发团队在确定流程管理器术语前,他们实现了基于工作流的方式。Gregor Hohpe和Bobby Woolf在《企业集成模式》一书中描述了这种模式。
流程管理器(Process Manager)
本节描述流程管理器的定义。在描述流程管理器之前,先简要回顾一下:CQRS如何使用消息在聚合和边界上下文之间进行通信。
消息(message)和CQRS
当您实现CQRS模式时,通常会考虑两种类型的消息来在系统中传递信息:命令和事件。
命令是命令式的;它们是对系统执行任务或操作的请求。例如,“预定X会议的两个地点”或“把Y发言人安排到z房间”。命令通常只被单个接收者处理一次。
事件是通知;它们通知相关方,并告诉他们已经发生了一些事情。例如,“付款被拒绝”或“创建了X类型的座位”。注意他们如何使用过去时态。事件被发布,并且可能有多个订阅者。
通常,命令是在一个有边界的上下文中发送的。事件的订阅者可以在发布它们的同一个有界上下文中,也可以在其他有界上下文中。
本参考指南中的“A CQRS and ES Deep Dive”一章详细描述了这两种消息类型之间的区别。
什么是流程管理器
在您使用聚合和有界上下文建模的复杂系统中,可能有一些业务流程涉及多个聚合,或在多个有界上下文中的多个聚合。 在这些业务流程中,参与聚合的会有多个不同类型的消息传递和交换。 例如,在会议管理系统中,购买会议座位的业务流程可能涉及订单聚合、预订聚合和支付聚合。 他们必须全部合作才能使客户完成购买。
图1显示了这些聚合为完成订单可能交换的消息的简化视图。数字标识消息顺序。
图1,不使用流程管理器的订单处理过程。
在图 1 所示的示例中,每个聚合都向执行流程中的下一步的聚合发送适当的命令。 Order 聚合首先向 Reservation 聚合发送 MakeReservation 命令以保留客户预定的座位。 预订座位后,Reservation 聚合会产生 SeatsReserved 事件以通知 Order 聚合,Order 聚合向 Payment 聚合发送 MakePayment 命令。 如果付款成功,Order 聚合会引发 OrderConfirmed 事件以通知 Reservation 聚合它可以确认座位预订(执行真正的扣减操作),以及告诉用户订单已完成。
图2,订单处理使用流程管理器。
图2所示的示例演示了与图1所示相同的业务流程,但这次使用了流程管理器。现在,不是每个聚合直接向其他聚合发送消息,而是由流程管理器来管理中间消息。
这似乎使流程变得复杂:有一个额外的对象(流程管理器)和一些更多的消息。然而,这种方法也有好处。
首先,聚合体不再需要知道流程的下一步是什么。最初,Order聚合需要知道,在进行预订之后,它应该通过向payment聚合发送消息来尝试进行支付。现在,它只需要知道已经创建了一个订单。
其次,消息流的定义现在位于单个位置,即流程管理器,而不是分散在整个聚合中。
在图1和图2所示的简单业务流程中,这些好处是有限的。但是,如果您的业务流程涉及6个聚合和数十条消息,那么好处就会更加明显。如果这是系统中易变的部分,业务流程经常发生更改,这种优势会尤其的明显。
在图3中,为了说明这一点,我们在流程中引入了等待列表。如果客户要求的某些座位无法预订,系统会将这些座位请求添加到等待列表中。要进行此更改,我们修改Reservation聚合,以引发SeatsNotReserved事件来报告有多少座位无法预订,以及SeatsReserved事件报告有多少座位可以预订。然后,进程管理器可以向WaitList聚合发送命令,将未完成的请求列在等待列表中。
图3,订单流程中使用流程管理器及等待聚合。
需要注意的是,流程管理器不执行任何业务逻辑。它只路由消息,并且在某些情况下在消息类型之间进行转换。例如,当它接收到一个SeatsNotReserved事件时,它会发送一个AddToWaitList命令。
什么时候使用流程管理器
使用流程管理器有两个关键原因:
- 当有界上下文使用大量事件和命令时,很难将其作为聚合之间点对点交互的集合进行管理。
- 当您希望在有界上下文中更容易修改消息路由时。流程管理器给出定义路由的简单方式。
什么时候不使用流程管理器
下面的列表列出了不使用流程管理器的原因:
- 如果有界上下文包含少量使用有限数量消息的聚合类型,则不应使用流程管理器。
- 您不应该使用流程管理器来实现域中的任何业务逻辑。业务逻辑属于聚合类型。
原文:https://docs.microsoft.com/en-us/previous-versions/msp-n-p/jj591569(v=pandp.10)