一行代码,保障分布式事务一致性—GTS:微服务架构下分布式事务解决方案

摘要: 虽然微服务如今如火如荼,但对其实践其实仍处于初级阶段。即便互联网巨头的实践也大可能是试验层面,鲜有核心业务系统微服务化的案例。GTS是目前业界第一款,也是惟一的一款通用的解决微服务分布式事务问题的中间件,并且能够保证数据的强一致性。本文将对GTS作出深刻解读。web

微服务倡导将复杂的单体应用拆分为若干个功能简单的、松耦合的服务,这样能够下降开发难度、加强扩展性、便于敏捷开发。概念2012年提出迅速火遍全球,被愈来愈多的开发者推崇,不少互联网行业巨头、开源社区等都开始了微服务的讨论和实践。根据Netflix云架构总监Adrian Cockcrof,Hailo有160个不一样服务构成,NetFlix有大约600个服务。国内方面,阿里巴巴、腾讯、360、京东、58等不少互联网公司都进行了微服务化改造。当前微服务的开发框架也有几十种之多,比较著名的有Dubbo、SpringCloud、thrift 、grpc等。redis

1 分布式事务解决方案及其弊端
虽然微服务如今如火如荼,但对其实践其实仍处于初级阶段。即便互联网巨头的实践也大可能是试验层面,鲜有核心业务系统微服务化的案例。而对于不少中小型互联网公司,鉴于经验、技术实力等问题,微服务落地更加困难。世界著名的软件架构大师Chris Richardson在《Introduction to Microservices》一文中也直接了当的指出了微服务当前存在的问题:spring

从单体应用拆分为分布式系统带来的复杂性。开发者须要选择或实现基于消息或者RPC模式的进程间通信机制,另外开发者也要写额外的代码去处理对于目的服务请求可能存在的请求缓慢或者请求不可用致使的局部故障问题。
单体应用拆分所致使的数据库架构的拆分。应用更新多个业务记录很是常见,单体应用实现也比较简单。然而在微服务架构下,应用不得不调用多个微服务去更新多个数据库。通常很难使用分布式事务解决,不只仅是由于CAP理论,还由于一些流行的NoSQL数据库和Message Queue系统压根也不支持(摊手)。最后还得绕回最终一致性方案,这个方案对开发者来说也是很是有挑战性。
测试微服务架构的应用也是更加复杂的。由于服务之间可能有诸多调用,测试一个服务将不得不启动其余服务。
部署、运维一个微服务架构的应用变的更加困难。微服务通常由大量的服务组成,每一个服务还有多个运行实例!将会有更多变化的部分须要去配置、部署、扩展、监控。此外还须要实现一个服务发现机制让其余服务找到它须要通讯的服务的地址。
对于第一和第三个问题,笔者认为随着RPC框架的成熟,已经逐渐获得解决。例如dubbo能够支持rmi、hessian、http、webservice、thrift、redis等多种通信协议,springcloud能够很是好的支持restful调用。spring体系下应用的测试也变的愈来愈简单。对于第四个问题,随着docker、devops技术的发展以及各公有云paas平台自动化运维工具的推出,微服务的部署与运维会变得愈来愈容易。sql

而对于Chris Richardson提到的第二个问题,如今尚未通用方案很好的解决微服务产生的事务问题。分布式事务已经成为微服务落地最大的阻碍,也是最具挑战性的一个技术难题。 为此,本文将深刻和你们探讨微服务架构下,分布式事务的各类解决方案,并重点为你们解读阿里巴巴提出的分布式事务解决方案----GTS。该方案中提到的GTS是目前业界第一款,也是惟一的一款通用的解决微服务分布式事务问题的中间件,并且能够保证数据的强一致性。docker

2 SOA分布式事务解决方案
在微服务以前,信息系统中的服务大多基于SOA的理念设计(SOA与微服务的区别),服务相对比较重。对于服务调用产生的分布式事务问题,在SOA时代,就有一些解决方案。比较著名的有基于XA协议的方案、TCC方案、消息最终一致性方案。数据库

2.1基于XA协议的方案
该方案最先由oracle提出用于解决跨数据访问的事务问题,是一种强一致性的解决方案,由事务协调器和本地资源管理器共同完成。事务协调器和资源管理器间经过XA协议进行通讯。XA协议实现的原理入下图所示,共分为两个阶段,也就是咱们常说的两阶段协议。
图片描述服务器

两阶段方案在解决数据库分布式事务问题方面应用很是普遍,oracle、Mysql等主流关系数据库均支持XA协议,并且ocenbase、DCDB等著名的分布式数据库也都基于两阶段协议。在解决服务事务问题上,其实 XA协议不是只能做用于单个服务内部的多资源场景,跨服务的多资源场景也是能够的,只不过须要额外的事务传递机制。但其都有致命的缺点,性能不理想。因为须要等到各分支事务都就绪后全局事务才开始提交,因此每一个事务锁定数据的时间较长,XA方案所以很难知足高并发场景。并且在解决微服务问题时XA方案的性能问题将会被放大。由于应用在访问服务的调用方式、网络环境等要比访问数据库复杂的多。例如,应用和其访问的数据库一般在一个局域网中,而其经过rpc调用的服务则可能属于另外一个网络或者在公网上,其时延更长、出故障的几率更高。这将致使数据锁定时间和系统并发度进一步下降。因此XA方案基本不适合解决微服务的事务问题。restful

2.2TCC方案
TCC方案应用是目前呼声最高,也是落地最多的一个方案。当前也有一些开源的TCC框架实现,如TCC-Transaction、ByteTCC。TCC方案实际上是两阶段方案的一种改进,其将本地资源管理器的功能融入到了业务实现中。其将整个业务逻辑显示的分红了Try、Confirm、Cancel三部分。try部分完成业务的准备工做,confirm部分完成业务的提交,cancel部分完成事务的回滚。基本原理以下图所示。网络

图片描述
事务开始时,业务应用会向事务协调器注册启动事务。以后业务应用会调用全部服务的try接口,至关于XA的第一阶段。若是有任何一个服务的try接口调用失败会向事务协调器发送事务回滚请求,不然发送事务提交请求。事务协调器收到事务回滚请求后会依次调用事务的confirm接口,不然调用cancel接口回滚,这至关于XA的第二阶段。若是第二阶段接口调用失败,会进行重试。架构

TCC方案经过经过三个接口很好的规避了长时间数据加锁的问题,业务表在每一个接口调用完毕便可释放,这很大程度上提升了业务的并发度,这也是TCC方案最大的优点。因此在SOA时期,TCC方案被不少金融、电商的业务系统大量使用。
固然TCC方案也有不足之处,集中表如今如下两个方面:

开发工做量大。它将部分资源管理器的功能融入到每一个服务的开发中,致使服务的每一个接口都须要实现try、confirm、cancle,还须要实现事务协调器,开发量不仅翻了一倍。
实现难度大。系统须要记录每一个应用的服务调用链路。我前面讲过rpc调用状况比较复杂,因为网络情况、系统故障等调用失败被视为常态,必须按照不一样的失败缘由实现不一样策略的回滚。为了知足一致性的要求,二阶段无论调用confirm仍是cancle都必须调用成功,若是一次调用不成功,事务协调器必须尝试重试。这就要求confirm和cancle接口必须实现幂等。
上述缘由致使TCC方案大可能是被研发实力较强、有迫切需求的大公司所采用。其将分布式事务变成一种所谓的“贵族技术”,中小型企业因为人员有限、技术实力薄弱,很难落地。并且笔者认为微服务倡导的是服务的轻量化、易部署,而TCC方案将不少事务的处理功能融入到业务中,对业务侵入性过高,致使服务逻辑复杂,比较适合比较重的服务。

2.3 消息事务一致性方案
消息一致性方案是经过消息中间件保证上、下游应用数据操做的一致性。基本思路是将本地操做和发送消息放在一个事务中,保证本地操做和消息发送要么二者都成功或者都失败。下游应用向消息系统订阅该消息,收到消息后执行相应操做。
如下单业务为例进行说明,下单基本流程是先存储订单信息,而后扣相应商品的库存,两个操做必须在一个事务中。以下图,业务应用首先调用订单服务,订单存储成功后,订单服务会经过消息处理服务投递订单消息到MQ。库存服务从MQ收到消息后进行扣库存操做,若是执行成功会向消息处理服务发送通知。消息处理服务会实时监测订单消息是否超时,若是超时会从新投递到MQ中,以驱动库存服务进行扣库存操做。若是扣库存操做执行失败后,库存服务后续还会从MQ接收到相同的订单消息,须要屡次重复执行,直到成功或者进行人工干预。库存服务须要实现幂等。

图片描述
消息方案从本质上讲是将分布式事务转换为两个本地事务,而后依靠下游业务的重试机制达到最终一致性。相对TCC方案来说,消息方案技术难度相对低,落地较容易,若是对一致性不敏感的应用也是一个不错的选择。美国著名电商e-bay以及国内的蘑菇街都作过尝试。消息一致性方案的不足之处是其对应用侵入性较高,应用须要基于消息接口进行改造,并且须要建设专门的消息系统,成本较高。

3 GTS--微服务分布式事务解决方案
GTS是一款分布式事务中间件,由阿里巴巴中间件部门研发,能够为微服务架构中的分布式事务提供一站式解决方案。GTS方案的基本思路是:将分布式事务与具体业务分离,在平台层面开发通用的事务中间件GTS,由事务中间件协调各服务的调用一致性,负责分布式事务的生命周期管理、服务调用失败的自动回滚。

GTS方案有三方面的优点,首先它将微服务从分布式事务中解放出来,微服务的实现不须要再考虑反向接口、幂等、回滚策略等复杂问题,只须要业务本身的接口便可,大大下降了微服务开发的难度与工做量。将分布式事务从所谓的“贵族技术”变为你们都能使用的“平民技术 ”,有利于微服务的落地与推广。 其次,GTS对业务代码几乎没有侵入,只须要经过注解@TxcTransaction界定事务边界便可,微服务接入GTS的成本很是低。第三,性能方面GTS也很是优秀,是传统XA方案的8~10倍。

3.1 基本原理
GTS中间件主要包括客户端(GTS Client)、资源管理器(GTS RM)和事务协调器(GTS Server)三部分。GTS Client主要完成事务的发起与结束。GTS RM完成分支事务的开启、提交、回滚等操做。GTS Server主要负责分布式事务的总体推动,事务生命周期的管理。
图片描述

GTS和微服务集成后的结构图如上图所示。GTS Client须要和业务应用集成部署,RM与微服务集成部署。当业务应用发起服务调用时,首先会经过GTS Client向TC注册新的全局事务。以后GTS Server会给业务应用返回全局惟一的事务编号xid。业务应用调用服务时会将xid传播到服务端。微服务在执行数据库操做时会经过GTS RM向GTS Server注册分支事务,并完成分支事务的提交。若是A、B、C三个服务均调用成功,GTS Client会通知GTS Server结束事务。假设C调用失败,GTS Client会要求GTS Server发起全局回滚。而后由各自的RM完成回滚工做。

3.2 GTS的关键机制
可用性
GTS服务也是由多个节点构成的高可用集群,能够弹性扩张,能够接收高并发的客户端请求。能够支持跨机房部署,支持同城容灾和两地三中心容灾。任何异常状况下的保证高可用。
自动回滚策略
当有微服务调用失败时,GTS服务能够驱动各微服务的RM替微服务完成调用的回滚工做。举个转帐的例子,转帐应用一般调用存款服务和扣款服务完成转帐功能。先调用扣款服务从A帐户扣掉100元,而后调用存款服务向B帐户中存款100元。若是转帐应用在调用存款服务失败时,GTS Client会要求GTS Server发起回滚,而后通知扣款服务对应的RM,RM会直接在A帐户增长100元。而后GTS Server通知转帐应用回滚成功。从这个过程能够看到,在调用服务失败后,其实微服务不用作任何工做,而是由RM替微服务执行反向操做,也很天然的避免了幂等操做。TCC方案中,事务协调器须要显示调用微服务的反向向接口,若是反向接口调用失败还须要不断重试。
可扩展性
有些状况下,应用须要调用第三方系统的接口或者不是基于GTS开发的微服,GTS没法接入到这些服务的实现中。此时须要用到GTS的MT模式。GTS的MT模式能够等价于TCC模式。
MT模式预留了一阶段和二阶段的提交接口,容许应用介入GTS的两阶段提交。应用将提交及回滚接口注册后,GTS会自动完成调用。

隔离级别
GTS目前支持读未提交和读已提交两种隔离级别。
3.3 GTS与其余方案的对比

  1. 和XA方案对比

相比XA方案,GTS更加通用,能够对上层业务屏蔽底层实现细节,对业务几乎没有侵入。这一点在微服务时代特别有用,微服务面对的是大量的中小企业,甚至是我的开发者,业务诉求不尽相同,普适、标准的分布式事务产品是很是有必要的,可让开发者从底层技术细节中脱离出来,更专一于业务逻辑的实现,从而得到更高效、快速的业务发展。两个方案均可以遵循ACID特性,均可以实现事务的强一致性。GTS性能要比XA方案高。

  1. 和TCC方案对比

GTS方案和TCC方案最大的区别是实现分布式事务实现的层面不一样。TCC方案选择从业务层面实现分布式事务功能,将事务的回滚、重试等功能在微服务中实现。而GTS选择从中间件层面解决分布式事务问题,对微服务几乎无侵入。两个方案均可以得到比较好的性能,均可以保证调用的一致性。TCC方案实现难度比较大,适合技术实力较强的团队。GTS方案能够实现事务的强一致性,另外采用GTS方案后微服务会更简单,耦合性也很是低。TCC主要提供开发框架,实现须要依赖业务方,而GTS是完整的分布式事务解决方案,全部分布式事务问题不须要业务方介入。

  1. 和消息最终一致性对比

相比消息方案,GTS方案侵入性很是低,能够实现数据的强一致性。采用消息方案,上下游服务之间有很强的耦合性,测试、部署都不是很方便,须要单独建设消息系统。不过消息方案实现相对简单,若是对一致性要求不高,也是一个选择。

3.4 GTS的应用场景
GTS可应用在涉及服务调用的多个领域,包括但不限于金融支付、电信、电子商务、快递物流、广告营销、社交、即时通讯、手游、视频、物联网、车联网等,详细介绍能够阅读 《GTS--阿里巴巴分布式事务全新解决方案》一文。

3.5 GTS的输出形式
GTS目前有三种输出形式:经过公有云平台输出、经过公网云服务输出、经过专有云平台输出。

1 经过公有云平台输出
这种输出形式主要面向阿里云用户。若是用户的业务系统已经部署到阿里云上,能够直接申请开通公有云GTS。开通后业务应用便可经过GTS保证服务调用的一致行。这种使用场景下,业务系统和GTS间的网络环境比较理想,GTS能提供更低的响应时间。
图片描述

公有云提供了比较丰富的与dubbo、SpringCloud等集成的样例,能够点击查看。

2 经过公网云服务输出
这种输出形式主要面向于非阿里云的用户,使用更加方便、灵活,业务系统只要能链接互联网便可享受GTS提供的云服务。在网络抖动和闪断的状况下,GTS仍能保证服务调用的一致性。在正常网络环境下,以包含两个本地事务的全局事务为例,事务完成时间在20ms左右,业务能够轻松实现1000TPS以上分布式事务,能够知足绝大多数业务系统的须要。也能够用于本地的开发和测试 。
图片描述
如今提供了sample-txc-simple和sample-txc-sample两个样例,sample-txc-simple是GTS的入门的基础样例,点击下载后,搭建好本地的数据库环境就能够直接运行样例。sample-txc-dubbo是GTS和dubbo框架集成的样例,也能够直接在本地机器运行。

3 经过专有云平台输出
这种形式主要面向于已建设了本身专有云平台的大用户,GTS能够直接部署到用户的专有云平台上,为专有云提供分布式事务服务。目前国家电网公司、中国邮政、浙江烟草等特大型企业的专有云都使用GTS,保证数据一致性。

3.6 GTS的使用方式
GTS对应用的侵入性很是低,使用也很是简单。下面以订单存储应用为例说明。订单业务应用经过调用订单服务和库存服务完成订单业务,服务开发框架为dubbo。

1 订单业务应用
在业务函数外围使用@TxcTransaction注解便可开启分布式事务。dubbo应用经过隐藏参数将GTS的事务xid传播到服务端。

@TxcTransaction(timeout = 1000 * 10)
public void Bussiness(OrderServiceInterface os,StockServiceInterface ss)
{
//获取xid
String xid = TxcContext.getCurrentXid();
//1:调用订单服务,建立订单
//经过dubbo的隐形参数将txcid传到服务端
RpcContext.getContext().setAttachment("xid",xid);
int ret = os.setOrder(new Order(pid,num,new Date()));//调用订单服务
//2:调用库存服务,扣库存
RpcContext.getContext().setAttachment("xid",xid);
}

2 服务端使用方式
库存服务

public int setStock(Stock sk) {
//经过dubbo上下文获取xid
String xid = RpcContext.getContext().getAttachment("xid");
//将事务id绑定到服务端txc的上下文
TxcContext.bind(xid,null);
//执行扣库存操做
ret  = jdbcTemplate2.update("update stock set number = number -? where pid = ?",new Object[]{sk.getPnum(),sk.getPid()});
return ret;
}

3.7 GTS的应用状况
GTS在知足事务ACID的前提下,普通配置的单服务器能够达到15000 TPS以上的超强性能(两个小时完成1亿多笔业务)。目前已经在淘宝、天猫、阿里影业、淘票票、阿里妈妈、1688等阿里各业务系统普遍使用,经受了16年和17年两年双十一海量请求的考验。某线上业务系统最高流量已达十万TPS(每秒钟10万笔事务)。GTS在阿里云及专有云上输出后,有不少用户经过GTS解决SpringCloud、Dubbo、Edas等微服务的分布式事务问题,包括国家电网、中国邮政、中国烟草、特步、浙江公安、德邦快递、一步共享科技等,涉及电力、物流、ETC、烟草、金融、零售、电商、共享出行等十几个行业,获得用户的一致承认。
图片描述
上图是GTS与SpringCloud集成,应用于某共享出行系统。业务共享出行场景下,经过GTS支撑物联网系统、订单系统、支付系统、运维系统、分析系统等系各统应用事务一致性,保证海量订单和数千万流水的交易。
原文连接

相关文章
相关标签/搜索