如何实现微服务架构下的分布式事务?

摘要:微服务架构下,如何克服分布式事务难题?

什么是微服务?微服务有什么优点和困难?

什么是微服务架构?

简而言之,微服务架构的系统是一个分布式的系统,按业务进行划分为独立的服务单元,解决单体系统的不足,同时也知足愈来愈复杂的业务需求。每一个微服务仅关注于完成一件任务并很好地完成该任务。算法

微服务架构的优点

  1. 将复杂的业务拆分红多个小的业务,每一个业务拆分红一个服务,将复杂的问题简单化。利于分工,下降新人的学习成本。
  2. 微服务系统是分布式系统,业务与业务之间彻底解耦,随着业务的增长能够根据业务再拆分,具备极强的横向扩展能力。
  3. 服务间采用 HTTP 协议通讯,服务与服务之间彻底独立。每一个服务能够根据业务场景选取合适的编程语言和数据库。
  4. 服务独立部署,每一个服务的修改和部署对其余服务没有影响。

虽然微服务有以上的优点,可是微服务实践仍处于探索阶段,不少中小型互联网公司,鉴于经验、技术实力等问题,微服务落地比较困难。著名架构师Chris Richardson指出,目前微服务主要存以下几方面困难:数据库

  1. 单体应用拆分为分布式系统后,进程间的通信机制和故障处理措施变的更加复杂。
  2. 系统微服务化后,一个看似简单的功能,内部可能须要调用多个服务并操做多个数据库实现,服务调用的分布式事务问题变的很是突出。
  3. 微服务数量众多,其测试、部署、监控等都变的更加困难。

随着RPC框架的成熟,第一个问题已经逐渐获得解决。例如Dubbo能够支持多种通信协议,Spring Cloud能够很是好的支持restful调用。对于第三个问题,随着Docker、DevOps技术的发展以及各公有云PaaS平台自动化运维工具的推出,微服务的测试、部署与运维会变得愈来愈容易。编程

而对于第二个问题,如今尚未通用方案很好的解决微服务产生的事务问题。分布式事务已经成为微服务落地最大的阻碍,也是最具挑战性的一个技术难题。下面将深刻和你们探讨微服务架构下,分布式事务的各类解决方案。segmentfault

微服务架构下,如何克服分布式事务难题?

什么是事务

事务是由一组SQL语句组成的逻辑处理单元,事务具备如下4个属性,一般简称为事务的ACID属性:安全

原子性(Atomicity):事务是一个原子操做单元,其对数据的修改,要么全都执行,要么全都不执行。服务器

一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着全部相关的数据规则都必须应用于事务的修改,以保持数据的完整性。restful

隔离性(Isolation):数据库系统提供必定的隔离机制,保证事务在不受外部并发操做影响的“独立”环境执行。数据库事务隔离级别由低到高依次为Read uncommitted、Read committed、Repeatable 、Serializable。架构

持久性(Durability):事务完成以后,它对于数据的修改是永久性的,即便出现系统故障也可以保持。并发

分布式事务典型场景:

银行转帐业务是一个典型分布式事务场景,一般包括如下三种状况:框架

A. 支行内转帐:同一银行的相同支行内转帐

B. 行内转帐:同一银行的不一样支行间转帐

C. 跨行转帐:不一样银行的系统进行转帐

对于传统集中式架构,A、B一般为本地事务,C为分布式事务。业务微服务改造后,转入、转出一般为不一样的微服务,同一个微服务也一般运行于不一样实例中。A可能变成一个分布式事务,也可能经过一些方法规避,在本地事务内完成。B和C很难规避,只能是分布式事务。

微服务最佳实践建议尽可能规避分布式事务,可是在不少业务场景(好比上面的B、C转帐场景),分布式事务是一个绕不开的技术问题。

分布式事务经常使用解决方案

为了解决分布式系统一致性问题,前人在性能和数据一致性的反反复复权衡过程当中总结了许多典型的协议和算法。其中,最经常使用的是两阶提交协议(2 Phase Commitment Protocol)。

两阶段提交方案

交易中间件与数据库经过 XA 接口规范,使用两阶段提交来完成一个全局事务, XA 规范的基础是两阶段提交协议。

第一阶段是表决阶段,全部参与者都将本事务可否成功的信息反馈发给协调者;第二阶段是执行阶段,协调者根据全部参与者的反馈,通知全部参与者,步调一致地在全部分支上提交或者回滚。

两阶段提交方案应用很是普遍,典型商用软件包括Oracle Tuxedo和IBM CICS。它的优势是对业务代码侵入较低,但缺点也很明显:

性能低下:因为 XA 协议自身的特色,它会形成事务资源长时间得不到释放,锁定周期长,并且在应用层上面没法干预,数据并发冲突高的场景性能不好。

单点问题:协调者在整个两阶段提交过程当中扮演着举足轻重的做用,一旦协调者所在服务器宕机,就会影响整个数据库集群的正常运行。好比在第二阶段中,若是协调者由于故障不能正常发送事务提交或回滚通知,那么参与者们将一直处于阻塞状态。

同步阻塞:两阶段提交执行过程当中,全部的参与者都须要遵从协调者的统一调度,期间处于阻塞状态而不能从事其余操做,效率及其低下。

所以,两阶段提交方案在互联网业务中不多使用,没法知足高并发需求。

为了这个弥补这种方案带来性能低的问题,你们又想出了不少种方案来解决,经过在应用层作文章,即入侵业务的方式,比较典型的是TCC 方案和基于可靠消息的最终一致性方案。

TCC事务方案

TCC事务模型在电商、金融领域落地较多。TCC方案实际上是两阶段提交的一种改进。其将整个业务逻辑的每一个分支显式的分红了Try、Confirm、Cancel三个操做。Try部分完成业务的准备工做,confirm部分完成业务的提交,cancel部分完成事务的回滚。基本原理以下图所示。

事务开始时,业务应用会向事务协调器注册启动事务。以后业务应用会调用全部服务的try接口,完成一阶段准备。以后事务协调器会根据try接口返回状况,决定调用confirm接口或者cancel接口。若是接口调用失败,会进行重试。

TCC方案让应用本身定义数据库操做的粒度,使得下降锁冲突、提升吞吐量成为可能,好比华为分布式事务中间件DTM性能极高,普通配置服务器能够支持全局事务1万+ TPS,分支事务3万+ TPS。 固然TCC方案也有不足之处,集中表如今如下两个方面:

业务侵入性强。业务逻辑的每一个分支都须要实现try、confirm、cancel三个操做,应用侵入性较强,改形成本高。

实现难度较大。为了知足一致性的要求,要充分考虑幂等操做,容许重复执行,也要防止资源悬挂,作好并发访问控制和数据可见性控制等。

上述缘由致使TCC方案大多被研发实力较强、有迫切需求的大公司所采用。微服务倡导服务的轻量化,而TCC方案中不少事务的处理逻辑须要应用本身编码实现,复杂且开发量大。

基于消息的最终一致性方案

消息一致性方案是经过消息中间件保证上下游应用数据操做的一致性。基本思路是将本地操做和发送消息放在一个本地事务中,保证本地操做和消息发送要么二者都成功或者都失败。下游应用向消息系统订阅该消息,收到消息后执行相应操做。

消息最终一致方案从本质上讲是将分布式事务转换为两个本地事务,而后依靠下游业务的重试机制达到最终一致性。基于消息的最终一致性方案对应用侵入性也很高,应用须要进行大量业务改造,成本很是高。

入侵代码的方案是基于现有情形“无可奈何”才推出的解决方案,实际上它们实现起来很是不优雅,好比TCC,一个事务的调用一般伴随而来的是对该事务接口增长一系列的反向操做,提交逻辑必然伴随着回滚的逻辑,这样的代码会使得项目很是臃肿,维护成本高。

针对上面所说的分布式事务解决方案的痛点,很显然,咱们理想的分布式事务解决方案确定是性能要好并且要对业务无侵入,业务层无需关心分布式事务机制的约束,作到事务与业务分离,也就是本文所重点推荐的非侵入事务。

非侵入事务方案

a. 典型架构

非侵入事务典型架构以下图所示:

事务核心组件包括:

Transaction Coordinator (TC): 事务协调器,分布式事务大脑,产生和维护全局事务、分支事务,推动事务提交与回滚的二阶段处理。TC Server以集群形式提供事务协调能力。

Transaction Manager (TM): 定义全局事务的边界,与事务协调器通讯以开启、提交或回滚全局事务。

Resource Manager (RM): 资源管理器,管理分支事务处理的资源,与事务协调器通讯以开启、结束事务分支,并接收事务协调器指令完成二阶段分支事务提交或回滚。

Lock Server (LS): 分布式锁服务器,能够经过它对进行中的分布式事务所操做的资源查询、加锁、放锁。

一个分布式事务称为一个全局事务,下面挂若干个分支事务,一个分支事务是一个知足 ACID 的本地事务。非侵入事务的核心思想是资源管理器拦截业务SQL,对其解析并作额外的一些数据处理,产生undo log并保存,一旦发生全局事务回滚,经过各个分支事务对应的undo log完成全部分支事务回滚。

你们很容易想到,两个全局事务并行修改了相同数据,可能会形成根据undo log完成回滚产生数据错误。解决的方法是经过Lock Server对事务所修改数据加锁,全局事务提交后当即放锁,全局事务回滚则等待分支事务回滚完成放锁。

b. 典型流程

典型分布式事务主要执行步骤以下:

1.TM请求TC开始新的全局事务,TC建立全局事务并返回全局事务ID(XID)。

2.根据XID构建事务上下文,经过微服务的调用链传播。

3.RM发现本身处于事务上下文,获得全局事务ID并解析SQL,产生undo log和分布式事务锁数据,请求TC建立分支事务。

4.TC 经过LS加锁,加锁成功后建立分支事务ID并返回。

5.RM 把分支事务ID与undo log关联,与业务原始SQL在一个本地事务内提交。

6.重复3~5,为全局事务范围内的每一个本地事务建立一个分支事务。

7.若是全局事务边界内没有任何异常,则TM请求TC提交全局事务;若是有异常,则TM请求TC回滚全局事务。

  1. TC标记全局事务状态,若是为提交则当即经过LS放锁。推动XID所对应全局事务下的全部分支事务进行二阶段处理,发送请求到RM。

9.RM完成分支事务的提交或回滚,并返回状态到TC。

10.TC对完成回滚的分支经过LS放锁。全部分支完成后,返回全局事务处理结果到TM。

二阶段事务处理比较关键,在此重点说明一下。

c. 分支事务提交

若是全局事务状态为提交,则对每一个分支发起分支提交,流程以下图所示:

RM收到分支事务提交请求,先保存分支事务的ID在队列中并返回。一个线程定时从队列中取出一批分支事务ID,构建SQL批量删除所对应的undo log日志。分支事务提交能够异步批量处理,是由于全局事务已经提交,undo log做为中间状态已经再也不重要,只要按期清理便可。

d. 分支事务回滚

若是全局事务状态为回滚或超时,则对每一个分支发起分支回滚,流程以下图所示:

RM收到分支事务回滚请求,开启一个本地事务,经过分支ID找到对应的undo log,构建回滚SQL语句并执行,删除undo log,而后提交本地事务。若是顺利完成,TC收到响应后经过LS清理该分支所占用资源。

e. 性能分析

非侵入事务相比XA两阶段提交一个重要性能优点在于锁定资源时间更短。实际业务中,咱们知道绝大多数事务状态为提交,不多比例为回滚。对于XA来讲,不管是提交仍是回滚,资源都是在二阶段释放。对本文所介绍的非侵入事务来讲,提交状态的全局事务,二阶段没有必要拿锁,只有少比例的回滚状态的全局事务,才须要在二阶段放锁。

非侵入事务不受限于数据库XA接口,实现彻底可控。TC、RM、LS这些关键组件对性能影响很大,良好的设计、实现能够取得很是高的性能。非侵入式事务实践证实,它能够轻松知足绝大多数高并发业务场景的性能需求。

典型核心业务系统分布式事务改造实例

华为云Stack为某运营商核心业务系统分布式事务改造,该客户业务在月初充值、扣费业务高峰期等常见的并发场景时,对分布式系统提出挑战:

  • 高并发的分布式事务访问帐户表,XA两阶段提交因为加锁时间长,严重影响业务。总体性能要求达1000+ TPS,传统或开源分布式事务难以知足高可用性与高性能要求。
  • XA事务与其余数据库操做的一致性问题。须要把XA事务做为DTM TCC事务的一个分支,将别的数据库操做是另外的分支。

华为云Stack混合云解决方案分布式事务中间件DTM经过一系列创新技术,提供高性能、高可用、高可靠、高安全、低侵入、易使用的分布式事务服务,支持TCC事务和非侵入事务两种模型,助力企业微服务化改造,优雅地解决分布式系统下数据一致性难题。

点击关注,第一时间了解华为云新鲜技术~

相关文章
相关标签/搜索