blog icon indicating copy to clipboard operation
blog copied to clipboard

分布式事务选型的取舍

Open TFdream opened this issue 6 years ago • 0 comments

分布式事务选型的取舍: https://mp.weixin.qq.com/s/HyWaYIJIqdLp1c_xrrzY1g

作者介绍

温卫斌,就职于中国民生银行信息科技部,目前负责分布式技术平台设计与研发,主要关注分布式数据相关领域。

微服务兴起的这几年涌现出不少分布式事务框架,比如ByteTCC、TCC-transaction、EasyTransaction以及最近很火爆的Seata。最近刚看了Seata的源码(v0.5.2),借机记录一下自己对分布式事务的一些理解。(3年前这类框架还没成熟,因项目需要自己也写过一个柔性事务框架)。

本文分五部分,首先明确分布式事务概念的演变,然后简单说下为什么大家不用XA,第三部分阐述两阶段提交的“提升”,第四部分介绍Seata的架构的亮点与问题,第五部分谈下分布式事务的取舍。

限于篇幅一些网上可搜索的细节本文不展开阐述(例如XA、Saga、TCC、Seata等原理的的详细介绍)。

一、分布式事务的泛化

提起分布式事务,最早指涉及的是多个资源的数据库事务问题。 wiki对分布式事务的定义:

A distributed transaction is a database transaction in which two or more network hosts are involved.

不过事务一词含义随着SOA架构逐渐扩大,根据上下文不同,可分为两类:

  • System transaction;
  • Business transaction。

前者多指数据库事务,后者则多对应一个业务交易。

与此同时,分布式事务的含义也在泛化,尤其SOA、微服务概念流行起来后,多指的是一个业务场景,需要编排很多独立部署的服务时,如何保证交易整体的原子性与一致性问题。这类分布式事务也称作长事务(long-lived transaction),例如一个定行程的交易,它由购买航班、租车以及预订酒店构成,而航班预订可能需要一两天才能确认。为了统一对概念的理解,本文默认指的都是这类长事务。

分布式事务概念泛化的同时,也带来了一个技术问题,微服务下这类分布式事务的ACID该如何保证?是否仍然可以用传统两阶段提交/XA去解决?很可惜,基于数据库的XA有点像扶不起的阿斗,中看不中用。

二、为什么XA大家都不用?

其实也并非不用,例如在IBM大型机上基于CICS很多跨资源是基于XA协议实现的分布式事务,事实上XA也算分布式事务处理的规范了,但在为什么互联网中很少使用,究其原因我觉得有以下几个:

  • 性能(阻塞性协议,增加响应时间、锁时间、死锁);
  • 数据库支持完善度(MySQL 5.7之前都有缺陷);
  • 协调者依赖独立的J2EE中间件(早期重量级Weblogic、Jboss、后期轻量级Atomikos、Narayana和Bitronix);
  • 运维复杂,DBA缺少这方面经验;
  • 并不是所有资源都支持XA协议;
  • 大厂懂所以不使用,小公司不懂所以不敢用。

准确讲XA是一个规范、协议,它只是定义了一系列的接口,只是目前大多数实现XA的都是数据库或者MQ,所以提起XA往往多指基于资源层的底层分布式事务解决方案。其实现在也有些数据分片框架或者中间件也支持XA协议,毕竟它的兼容性、普遍性更好。

三、两阶段提交的“提升”

基于数据库的XA协议本质上就是两阶段提交,但由于性能原因在互联网高并发场景下并不适用。如果数据库只能保证本地ACID时,那么其中出现交易异常后,如何实现整个交易原子性A,从而保证一致性C呢?另外在处理过程中如何保证隔离性呢?

最直接的方法就是按照逻辑依次调用服务,但出现异常怎么办?那就对那些已经成功的进行补偿,补偿成功就一致了,这种朴素的模型就是Saga。但Saga这种方式并不能保证隔离性,于是出现了TCC。在实际交易逻辑前先做业务检查、对涉及到的业务资源进行“预留”,或者说是一种“中间状态”,如果都预留成功则完成这些预留资源的真正业务处理,典型的如票务座位等场景。

当然还有像Ebay提出的基于消息表,即可靠消息最终一致模型,但本质上这也属于Saga模式的一种特定实现,它的关键点有两个:

  • 基于应用共享事务记录执行轨迹;
  • 然后通过异步重试确保交易最终一致(这也使得这种方式不适用那些业务上允许补偿回滚的场景)。

这类分布式事务场景并不是微服务才出现的,在SOA时代其实就有了,常见的Saga、TCC、可靠消息最终一致等模型也都是很多年前就有了,只是最近几年随着微服务兴起,这些方案又重新被人关注了起来。

「Saga」参考链接:https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf

仔细对比这些方案与XA,会发现这些方案本质上都是将两阶段提交从资源层提升到了应用层。

  • Saga的核心就是补偿,一阶段就是服务的正常顺序调用(数据库事务正常提交),如果都执行成功,则第二阶段则什么都不做;但如果其中有执行发生异常,则依次调用其补偿服务(一般多逆序调用未已执行服务的反交易)来保证整个交易的一致性。应用实施成本一般。
  • TCC的特点在于业务资源检查与加锁,一阶段进行校验,资源锁定,如果第一阶段都成功,二阶段对锁定资源进行交易逻辑,否则,对锁定资源进行释放。应用实施成本较高。
  • 基于可靠消息最终一致,一阶段服务正常调用,同时同事务记录消息表,二阶段则进行消息的投递,消费。应用实施成本较低。

具体到基于这些模型实现的分布式事务框架,也多借鉴了DTP(Distributed Transaction Processing)模型。

DTP(Distributed Transaction Processing)参考链接:http://pubs.opengroup.org/onlinepubs/009680699/toc.pdf

▲ DTP模型

  • RM负责本地事务的提交,同时完成分支事务的注册、锁的判定,扮演事务参与者角色。
  • TM负责整体事务的提交与回滚的指令的触发,扮演事务的总体协调者角色。

不同框架在实现时,各组件角色的功能、部署形态会根据需求进行调整,例如TM有的是以jar包形式与应用部署在一起,有的则剥离出来需要单独部署(例如Seata中将TM的主要功能放到一个逻辑上集中的Server上,叫做TC( Transaction Coordinator ))

四、Seata架构得与失

TFdream avatar Aug 06 '19 06:08 TFdream