来了!微服务中的事务处理
一个微服务完成工作的一个业务单元。在大多数情况下,一个事务的范围就是工作的一个业务单元;因此,事务被自动包含在一个服务里。例如,一个“借记储蓄银行账户”操作可以被原子化,...
一个微服务完成工作的一个业务单元。在大多数情况下,一个事务的范围就是工作的一个业务单元;因此,事务被自动包含在一个服务里。例如,一个“借记储蓄银行账户”操作可以被原子化,而且事务完整性可以确保这个操作在服务的范围内。
然而,也许有业务场景需要你运行跨多个服务的多个工作业务单元,这些工作单元是由不同管辖范围的不同的团队编写的。因为这样业务流程跨越多个服务的边界,确保事务完整性就变成了一个挑战。有多种策略可以应对这一挑战。
以我们都很熟悉的在线“信用卡还款”作为一个具体的例子, 还款需要两个操作的编排配合,“借记储蓄银行账户”和“信用卡账户”是由不同的管辖范围来处理的。在这种情况下,“信用卡还款”是一个跨两个服务的复合操作。储蓄借记和信用还贷操作应该同时发生或同时不发生。因此这给经典架构提出了一个挑战:我们要如何确保跨越了多个分布式服务执行的操作的事务完整性。
我们首先会想到采用通过复合服务“信用卡还款”协调的分布式事务作为一种策略。然而,分布式服务在扩展性和稳定性上存在问题,例如可能会导致死锁,因此不建议这样做。
补偿事务
一个更可行的策略是让“信用卡还款”的两个操作独立地执行。如果复合服务在储蓄借记操作完成后检测到信用还贷的操作失败,它会通过发送一个等价的贷方分录(credit entry)回滚储蓄账户的操作。这个贷方分录就是一个补偿事务。
但是也可能会有使用补偿策略反而影响事务完整性的场景。其中的一个场景就是在储蓄借记的操作执行完毕之后,信用还贷的操作执行开始之前,复合服务挂掉了。多种模式可以用来处理这种事务中间的失败。下面我们讨论一下这三种模式。
状态仓库
传送名单(Routing Slip)
流程管理器
状态仓库
复合服务在一个状态仓库记录了所有的状态改变。如果复合服务挂了,状态仓库可以用来找到和恢复不完整的事务。
传送名单
另一个常用的有弹性的方法是使复合的“信用卡还款”异步操作。复合服务在传送名单中用两个请求命令(一个给储蓄账户的指令和一个给信用账户的指令)创建了一个信息。这个信息从传送名单被发送到借记储蓄服务。借记储蓄服务执行第一个命令,并在将信息交给完成信用还贷操作的信用服务之前丰富传送名单。如果中间发生了失败,这个信息会被传送到错误队列,复合服务可以在有需要时从错误队列查看状态、错误状态和补偿措施。
流程管理器
传送名单的可替代方法是流程管理器,流程管理器监听储蓄借记和信用还贷操作的产生的事件,决定补偿还是完成事务。
在相同的限定上下文内的折叠操作
举另一个例子, 两个储蓄账户间的金额转移可以通过调用两次“储蓄账户”微服务的传统方式完成,即一次操作针对起点的账户的借记,另一次操作针对终点的账户的贷入。这种方式在事务处理上的考虑和上面所述的是相似的。然而,在这种情况下,由于借记和贷入操作都在“储蓄账户”的相同管辖范围内,“账户金额转移”逻辑可以只在执行借记和贷入操作的同一的微服务里面执行。这简化了事务处理的边界。
我们讨论了处理微服务中的事务问题的各种模式。根据您的使用案例,可以从上述选项中采用最佳方法。
长按二维码 ▲
订阅「架构师小秘圈」公众号
如有启发,帮我点个在看,谢谢↓
更多推荐
所有评论(0)