微服务架构中分布式事务实现方案怎样何取舍

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介:

提起微服务架构,不可避免的两个话题就是服务治理和分布式事务。数据库和业务模块的垂直拆分为我们带来了系统性能、稳定性和开发效率的提升的同时也引入了一些更复杂的问题,例如在数据一致性问题上,我们不再能够依赖数据库的本地事务,对于一系列的跨库写入操作,如何保证其原子性,是微服务架构下不得不面对的问题。

1 分布式事务解决方案

针对分布式系统的特点,基于不同的一致性需求产生了不同的分布式事务解决方案,追求强一致的两阶段提交、追求最终一致性的柔性事务和事务消息等等。各种方案没有绝对的好坏,抛开具体场景我们无法评价,更无法能做出合理选择。在选择分布式事务方案时,需要我们充分了解各种解决方案的原理和设计初衷,再结合实际的业务场景,从而做出科学合理的选择。

2 强一致解决方案

2.1 两阶段提交

两阶段提交算法中有两种角色:事务协调者和事务参与者,一个事务一般会涉及多个事务参与者,具体的两阶段过程如下图所示:

第一阶段:写库操作完成后协调者向所有参与者发送Prepare消息,询问各参与者的本地事务是否可以提交,参与者根据自身情况向协调者返回可以或不可以;

第二阶段:协调者收到所有参与者的反馈后,如果全部返回的是可以提交则向所有参与者发送提交事务命令。只要有一个参与者返回的是不能提交,则向所有参与者发送回滚命令。如下图所示:
_1_
图1 两阶段提交

在上述的两阶段模型中,事务提交过程中有可能出现协调者或个别参与者宕机的情况,但多数情况下参与事务的节点可以通过询问其他节点得知事务状态,做出正确的操作。但在极端情况下事务有可能处于未知状态。我们分析下下面这个场景:当协调者发送提交指令后宕机,而唯一收到提交指令的参与者完成提交后也宕机了,此时没有节点知道事务应该提交还是回滚,事务处于未知状态,所以在这种极端情况下可能造成数据的不一致。针对两阶段的缺陷,又提出了三阶段提交协议。

2.2 三阶段提交

三阶段提交是将第二阶段拆分成预提交和确认提交两个阶段。这样在事务提交过程中,无论哪个节点宕机,只要有一个存活节点处于预提交或是提交状态我们都可以确定事务是可以提交的(第一阶段已经确认事务可以提交),反之如果没有处于这两种状态的节点,则回滚事务。

_2_
图2 三阶段提交

从上面的分析可以看到,无论是两阶段还是三阶段最后的“提交”都是一个耗时极短的操作,即使在分布式系统中失败的概率也是非常小的,所以我们可以认为两阶段提交基本能够保证分布式事务原子性。

3 落地方案

上面介绍的只是理论基础,XA规范就是基于两阶段提交的理论模型提出的分布式事务规范,规范中的资源管理器相当于事务参与者;事务管理器相当于事务协调者,目前很多主流的关系数据库都实现了XA接口。

落地到实际应用中我们会发现两阶段提交存在的一些问题:

  1. 数据库产品要保证数据完成性,写入需要加锁,所以在整个分布式事务协调过程中可能造成数据库资源锁定时间过长,不适合并发高以及子事务生命周期较长的业务场景;
  2. XA规范要求事务管理器本地记录事务执行状态,所以事务管理器作为有状态服务不支持事务异地恢复;

XA能够最大程度保证数据的一致性,但在高并发场景下性能衰减非常严重,所以在数据一致性需求上如果不是“强一致”,不建议使用。

3.1 最终一致性解决方案

在我们大多数的业务场景中,追求的都是数据的最终一致性,业界也提出了很多柔性事务的解决方案,可以很大程度上保证数据的一致性,我们可以根据实际场景来权衡使用。具体的解决方案有很多,总结其设计思路可以分为下面3种模型:

3.1.1 TCC(Try-Confirm-Cancel)

TCC将事务分为Try,Confirm,Cancel三个阶段。

  1. Try阶段:尝试执行业务,预留资源;
  2. Confirm阶段:确认执行业务,使用Try阶段资源;
  3. Cancel阶段:取消执行业务,释放Try阶段预留的资源;

我们用一个转账汇款的业务场景,说明下TCC的具体过程。例如:张三给李四转账100元,一次转账业务由两个本地事务组成:1、张三账户扣减100元;2、李四账户增加100元。

事务成功处理流程如图3:

_3_Try_Confirm_
图3 Try-Confirm事务成功处理流程

事务失败处理流程如图4:

_4_Try_Cancel_
图4 Try-Cancel事务成功处理流程

Try阶段:

1、检查张三账户,满足要求账户扣减100元,记录扣减事件(预留资源);

2、检查李四账户有效性;

Confirm:

如果Try成功,李四账户增加100元,事务完成;

Cancel:

如果Try失败,张三账户增加100元,删除扣减事件记录(释放预留资源),事务取消。

从性能角度分析,TCC过程没有对资源加锁,对系统并发性能几乎没有影响,只是会有些额外辅助操作。需要注意,在这个模型中要保证数据一致性有两个技术难点需要解决:

  1. 需要有类似事务管理器的角色保证TCC过程的完整性;
  2. Confirm和Cancel方法需要保证幂等(由于不可避免的重试操作必须要保证幂等);

TCC对业务侵入非常大,对RD同学十分不友好,业务改造成本相当高。

3.1.2 SAGA模型

SAGA模型把一个分布式事务拆分为多个本地事务,每个本地事务都有相应的执行模块和补偿模块,当事务中任意一个本地事务出错时,可以通过调用对应的补偿方法恢复之前的事务,从而达到数据的最终的一致性。SAGA的事务管理器负责在事务失败时执行补偿逻辑,可以通过调用执行模块的逆向操作(例如执行子事务时同时生成逆向SQL)或调用业务开发人员提供的补偿方法(需要保证补偿的幂等性)来实现。

可以看到,SAGA虽然对业务造成一定的侵入,但当相对TCC已经有好很多了,而且,事务管理器理论上可以做到向后补偿(撤销所有已完成操作,恢复到事务开始状态)或向前补偿(继续完成未完成事务,使业务请求得到成功处理,更符合业务预期)。

3.1.3 MQ事务消息

MQ事务消息对分布式事务模型进行了简化,重点不再是保证所有子事务的原子性,而是保证本地事务和发送MQ消息的原子性,我们可以利用这一特点,将分布式事务转化成本地事务和若干发送MQ消息的操作,然后要求消费方确保消费成功。利用MQ事务消息,在系统中去掉了TCC和SAGA方案中的事务管理器角色,简化了分布式事务模型,同时这也是对业务侵入最低最友好的方案(不用提供补偿接口)。

当然这里也有两个基本前提:

  1. MQ系统保证消息能不丢失;
  2. 消费方确保消费幂等(保证不丢失,就很难避免重复消费)。

需要注意的是,MQ事务消息简化了事务模型、降低了业务侵入,所以对数据一致性的保证保障也就相对比较低了。

  1. 总结

柔性事务解决方案中,虽然SAGA和TCC看上去可以保证数据的最终一致性,但分布式系统的成产环境复杂多变,某些情况是可以导致柔性事务机制失效的,所以无论使用那种方案,都需要最终的兜底策略,人工校验,修复数据。

我们综合对比下几种分布式事务解决方案:

一致性保证:XA > TCC = SAGA > 事务消息

业务友好性:XA > 事务消息 > SAGA > TCC

性 能 损 耗:XA > TCC > SAGA = 事务消息

最后,在设计系统时我们一定要结合业务自身的一致性需求,选择恰当的方案。可以看到对数据一致性保障越高的方案其开发成本、维护难度和系统性能损耗就越大,一定不要一味的追求高大上的方案,对系统过度设计。

相关实践学习
RocketMQ一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
2天前
|
敏捷开发 监控 数据管理
构建高效微服务架构的五大关键策略
【4月更文挑战第20天】在当今软件开发领域,微服务架构已经成为一种流行的设计模式,它允许开发团队以灵活、可扩展的方式构建应用程序。本文将探讨构建高效微服务架构的五大关键策略,包括服务划分、通信机制、数据管理、安全性考虑以及监控与日志。这些策略对于确保系统的可靠性、可维护性和性能至关重要。
|
3天前
|
消息中间件 监控 持续交付
构建高效微服务架构:后端开发的进阶之路
【4月更文挑战第20天】 随着现代软件开发的复杂性日益增加,传统的单体应用已难以满足快速迭代和灵活部署的需求。微服务架构作为一种新兴的分布式系统设计方式,以其独立部署、易于扩展和维护的特点,成为解决这一问题的关键。本文将深入探讨微服务的核心概念、设计原则以及在后端开发实践中如何构建一个高效的微服务架构。我们将从服务划分、通信机制、数据一致性、服务发现与注册等方面入手,提供一系列实用的策略和建议,帮助开发者优化后端系统的性能和可维护性。
|
13天前
|
Kubernetes 安全 Java
构建高效微服务架构:从理论到实践
【4月更文挑战第9天】 在当今快速迭代与竞争激烈的软件市场中,微服务架构以其灵活性、可扩展性及容错性,成为众多企业转型的首选。本文将深入探讨如何从零开始构建一个高效的微服务系统,覆盖从概念理解、设计原则、技术选型到部署维护的各个阶段。通过实际案例分析与最佳实践分享,旨在为后端工程师提供一套全面的微服务构建指南,帮助读者在面对复杂系统设计时能够做出明智的决策,并提升系统的可靠性与维护效率。
|
2天前
|
存储 关系型数据库 分布式数据库
电子好书发您分享《PolarDB分布式版架构介绍PolarDB分布式版架构介绍》
**《PolarDB分布式版架构介绍》电子书分享:** 探索阿里云PolarDB分布式设计,采用计算存储分离,借助GMS、CN组件实现大规模扩展。[阅读更多](https://developer.aliyun.com/ebook/8332/116553?spm=a2c6h.26392459.ebook-detail.5.3b3b2ccbVVjjt0)
12 3
|
2天前
|
存储 关系型数据库 分布式数据库
电子好书发您分享《PolarDB分布式版架构介绍》
**探索PolarDB分布式版:阿里巴巴云的高扩展数据库解决方案,采用计算存储分离架构,确保高性能和弹性扩展。[阅读详情](https://developer.aliyun.com/ebook/8332/116553?spm=a2c6h.26392459.ebook-detail.5.33ac2ccbVd9TB2)**
90 7
|
5天前
|
机器学习/深度学习 运维 Prometheus
探索微服务架构下的系统监控策略
【4月更文挑战第18天】在当今快速迭代和持续部署盛行的软件工程实践中,微服务架构因其灵活性和可扩展性受到企业青睐。然而,随着服务的细粒度拆分和网络通信的增加,传统的监控手段已不再适用。本文将探讨在微服务环境中实施有效系统监控的策略,包括日志聚合、性能指标收集、分布式追踪以及异常检测等关键技术实践,旨在为读者提供构建稳定、可靠且易于维护的微服务系统的参考指南。
9 0
|
5天前
|
监控 持续交付 开发者
构建高效微服务架构:后端开发的新趋势
【4月更文挑战第18天】在数字化转型的浪潮中,微服务架构已成为企业提升系统灵活性、加速产品迭代的关键。此文深入探讨了构建高效微服务架构的实践方法,包括服务划分原则、容器化部署、持续集成/持续部署(CI/CD)流程以及监控与日志管理等关键技术点。通过分析具体案例,揭示了微服务在提高开发效率、降低维护成本及促进团队协作方面的显著优势。
|
6天前
|
负载均衡 Java 开发者
细解微服务架构实践:如何使用Spring Cloud进行Java微服务治理
【4月更文挑战第17天】Spring Cloud是Java微服务治理的首选框架,整合了Eureka(服务发现)、Ribbon(客户端负载均衡)、Hystrix(熔断器)、Zuul(API网关)和Config Server(配置中心)。通过Eureka实现服务注册与发现,Ribbon提供负载均衡,Hystrix实现熔断保护,Zuul作为API网关,Config Server集中管理配置。理解并运用Spring Cloud进行微服务治理是现代Java开发者的关键技能。
|
7天前
|
监控 JavaScript 安全
构建微服务架构下的API网关
【4月更文挑战第15天】在微服务架构中,API网关扮演着至关重要的角色。它作为系统的唯一入口,不仅负责请求的路由、负载均衡和认证授权,还涉及到监控、日志记录和服务熔断等关键功能。本文将探讨如何构建一个高效且可靠的API网关,涵盖其设计原则、核心组件以及实现策略,旨在为后端开发人员提供一套实用的指导方案。
19 4
|
8天前
|
监控 负载均衡 API
构建高性能微服务架构:后端开发的最佳实践
【4月更文挑战第14天】 在当今快速发展的软件开发领域,微服务架构已成为构建可扩展、灵活且容错的系统的首选方法。本文深入探讨了后端开发人员在设计和维护高性能微服务时需要遵循的一系列最佳实践。我们将从服务划分原则、容器化部署、API网关使用、负载均衡、服务监控与故障恢复等方面展开讨论,并结合实际案例分析如何优化微服务性能及可靠性。通过本文的阅读,读者将获得实施高效微服务架构的实用知识与策略。