假设我们的业务规则说,当用户下订单时,如果产品的价格在用户的信用限额/余额之内,则订单将被履行。否则将无法实现。看起来真的很简单。
这在整体/单体应用中非常容易实现。整个工作流程可以视为1个单事务。当所有内容都在单个数据库中时,提交/回滚很容易。对于具有多个数据库的分布式系统,这将非常复杂!首先让我们看一下我们的架构,看看如何实现它。
我们有一个带有其自己的数据库的订单服务,该数据库负责订单管理。同样,我们还提供付款服务,负责管理付款。因此,订购服务接收到该请求,并与付款服务核对用户是否有余额。如果付款服务响应“确定”,则订购服务将完成订单,付款服务将扣除付款。否则,订单服务将取消订单。对于非常简单的业务要求,这里我们必须通过网络发送多个请求。
在传统的系统设计方法中,订购服务仅发送HTTP请求以获取有关用户信用余额的信息。这种方法的问题是订单服务假定付款服务将始终启动并运行。付款服务上的任何网络问题或性能问题都将传播到订购服务。这可能会导致不良的用户体验,并且我们也可能会损失收入。
让我们看看如何通过使用事件溯源的Saga模式来处理松散耦合的分布式系统中的事务。
跨越多个微服务的每个业务交易事务都被分成特定于微服务的本地交易事务,并按顺序执行它们以完成业务工作流程。它被称为Saga。它可以通过两种方式实现。
- 编舞方法
- 编排方法
在本文中,我们将讨论使用事件源的基于编排的方法:基于编排的Saga。
事件溯源
在这种方法中,对应用程序状态的每次更改都被捕获为一个事件。此事件存储在数据库中(出于跟踪目的),并且还发布在事件总线中,供其他方使用。
订单服务收到创建新订单的命令。该请求将作为订单创建的事件进行处理并引发。这里要注意的几件事。
- 订单创建事件基本上会通知新订单请求已收到,并由订单服务保持为“待处理”状态。尚未实现。
- 事件对象将始终以过去时态命名,因为它已经发生了!
现在,付款服务可能会对收听这些事件以及批准/拒绝付款感兴趣。即使这些也可以视为事件。付款批准/拒绝事件。订单服务可能会监听这些事件,并履行/取消其最初收到的订单请求。
这种方法有很多优点。
- 没有服务依赖性。付款服务不必始终保持正常运行。
- 松耦合
- 水平缩放
- 容错
业务工作流的实现如下所示。
- order-services收到新订单的POST请求
- 它将订单请求以ORDER_CREATED状态放置在数据库中并引发一个事件
- 支付服务监听事件,确认信用额度
- order-service根据信用保留状态完成订单或拒绝订单。
在这里有一个完整的工作项目。您可以克隆代码并运行以在此处进行演示。确保您已建立并运行本地kafka群集。您可以使用此docker-compose文件 运行本地kafka集群。
状态更新
一旦订单服务完成订单并引发另一个事件。运送服务会监听事件,并负责将包装和运送到给定的用户地址。订单服务可能会再次监听那些事件,从而将其数据库更新为order_shipped状态。
正如我们前面提到的,提交/回滚跨多个微服务的事务非常具有挑战性。每个服务都应具有事件处理程序,以便针对它正在侦听的每个事件来提交/回滚事务以维护数据一致性!