深入浅出分布式事务

1、背景

随着互联网应用的兴起,伴随而来的业务出现井喷式增长,用户量也相比传统应用出现了陡增,原来用户完成业务只需要一个单台的业务服务器,演变成了涉及多服务、多应用协作完成一项业务操作。最早的应用或者说业务刚开始时,采用单体应用架构就能满足用户的使用,业务流程也同样简单,随着用户量的增加,系统最先考虑的就是通过垂直拆分,将原来单一应用拆成多个应用,最经典的场景就是电商网站,最开始创业时可能是一个系统,在第一次拆分的时候就会拆分为用户系统,订单系统,支付系统,交易系统等等。随着交易量的进一步增加,交易业务突破瓶颈,随之而来的就是系统需要进行水平扩展,比如在业务的垂直拆分后,交易系统的访问量增加后,需要多交易系统进行水平扩展,将单一交易系统扩展的水平多台,从而提高系统的并发度,保证业务的高可用。

在系统的垂直拆分,水平扩展的背后,伴随着的变化,就是从单体应用系统中使用单一数据库,需要扩展的多台数据库(通过业务拆分数据库,或者做分库分表),那么一个业务的完成就由单一的数据库变成了多台数据库服务协作完成,而数据与数据在某些场景下又必须保证一致性,比如在电商网站购买一件商品,库存扣减成功就必须付款成功,用户付款成功后还需要保证积分赠送成功等等,在这些场景下,现有的单机数据库事务就不能满足业务要求,不能保证业务的原子性,不能保证数据的一致性。故而就需要分布式事务来保证业务操作的原子性,一致性,隔离性,和持久性。

2、单机事务&分布式事务

2.1、单机事务

在讲解分布式事务前,我们先回顾一下单机事务主要有哪些特性:

  • 原子性:原子性是指事务的操作都是原子的,操作要么全部成功,要么失败全部回滚;
  • 一致性:一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态;
  • 隔离性:隔离性是指事务的操作之间是相互隔离的,互不干扰,多个事务并发执行时,就感觉像单一事务执行一样,达到预期结果;
  • 持久性:持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作;

以上的事务特性,在业务上我们都是依赖数据库去实现的。单机事务能够保证以上特性,其实说的直接一些就是,目前我们业务系统实现的所有事务操作,都是依赖于数据库实现的。而数据库如何实现事务的,以及如何保证以上的四个特性不是本文的重点,感兴趣的同学可以自行研究数据库事务。

单机事务处理流程如下图描述:

img

2.2、分布式事务

如背景章节中的描述,在业务进行拆分后,一个业务上的原子操作可能由多个分布在不同的业务系统共同完成,那么就将原来的一个单机的数据库事务,间接的变成了由多个数据库事务协作完成,故而就引入了分布式事务问题。又特别是在现在微服务大行其道的情况下,很多互联网公司都在做业务拆分,做服务化,那么随之而来的必然就是分布式事务问题,目前做服务化后,分布式事务就成了公司的痛点,成为了微服务落地的最大障碍,也是最具挑战的技术难题,解决方案也是百花齐放,各不相同,为此,本文将深入探讨微服务架构下的分布式事务解决方案。分布式事务简单描述如下:

img

如上图所示,在服务化后,整个业务操作由事务 A 和事务 B 构成,只有两个业务操作都完成后,才能标识整个业务完成;所以如果 A 事务完成,B 事务未完成,或者 B 事务完成时,

系统间出现超,主业务没有收到 B 的结果状态,故而主业务就标识为整个业务执行失败,但是事务 B 本质上是成功的,所以就会出现整个业务系统的状态不一致的问题;

3、分布式事务理论基础

如上描述的问题,是分布式系统中常见的分布式系统事务问题,业界也有对应的解决方案,如:CAP,BASE 理论,两阶段协议,三阶段协议,PAXOS 协议等,总体来讲分布式事务理论协议主要分为两大类:

  • 1、提交协议:所有事务活动的参与者都要完成提交后才能保证数据一致性。主要有:两阶段提交协议,三阶段提交协议

  • 2、投票协议:所有事务活动参与者中只要有过半数的参与者提交就能保证数据一致性。主要有:PAXOS,Raft,ZAB协议等

根据以上说明,下面我们就来描述这些协议理论基础,便于我们理解分布式事务。

说明:本文重点讨论提交协议中的两阶段协议,该协议是一切分布式事务协议的分析起点,理解透了两阶段协议,对其他协议的理解会更加容易。

3.1、CAP理论

CAP理论作为分布式系统的基石,CAP理论告诉我们,任何基于网络共享系统,最多只能满足一致性 (C:Consistency)、可用性(A:Availability)和分区容错性(P:Partition tolerance)这三个要素中的两个要素。

  • 1、一致性 (C:Consistency)

在分布式系统下,为了保证系统的高可用,数据是需要进行多份拷贝做数据备份(或者为了保证数据的数据的读写分离,同一数据需要分布在不同的系统中)。数据一致性是指在多个副本之间(或多份数据之间)是否能够保持一致性。在一致性的需求下,当一个系统在数据一致的情况下执行的更改操作后,应该保证系统的数据仍然处于一致的状态。

对于一个将副本数据分布在分布式不同节点上的系统来说,如果第一个节点对节点进行了更新,第二个节点却没有完成更新操作,那么在第二个节点上的数据与第一个节点的数据就不一致,就可能导致在第二个节点上读取的数据不正确,这就是比较典型的分布式系统下数据不一致的场景。

  • 2、可用性(A:Availability)

在分布式环境下,可用性是指系统提供的服务一直处于可用的状态,对于任何用户的请求,总是能够在一定的时间内做出响应,返回结果。这里需要重点说明“一定时间”与“返回结果”。

“一定时间”是指,对于用户的请求操作,系统必须能够快速响应结果,如果处理时间超出一定的范围,调用方可能自行断开连接,标识为服务不可用或服务响应变慢,导致业务受到影响,接口的性能指标是能比较直观的反应在tp99耗时,QPS/TPS

“返回结果”是系统的可用性的重要指标,它要求系统在完成对应的请求处理后,能够按照接口定义,响应正确的结果。所有的影响结果能够明确地反应出对请求的处理结果,不管是成功或失败,都能够明确表示。

  • 3、分区容错性 (P:Partition tolerance)

由于分布式系统是通过网络进行通信,网络是不可靠的,当出现任意的网络分区出现故障的时候,仍然能够保证服务对外提供一致性和可用性的服务。换句话说,分区容错是站在分布式系统的角度,对访问本系统的调用方的一种承诺。只要不出现整个网络环境的不可用,分布式系统都能保证提供服务。

既然一个分布式系统无法同时满足一致性、可用性、分区容错性三个特点,所以我们就需要三者中选取两者:

说明如下:

选择 说明
CA 放弃分区容错性,保证一致性和可用性,其实就是传统的单机数据库的选择。
AP 放弃一致性(这里说的一致性是强一致性),追求分区容错性和可用性,这是很多分布式系统设计时的选择,例如很多 NoSQL 系统就是如此。
CP 放弃可用性,追求一致性和分区容错性,基本不会选择,网络问题会直接让整个系统不可用。

需要说明的是,对于一个分布式系统来讲,分区容错性是一个最基本的要求,因为既然是一个分布式系统,那么必然会部署到不同的网络节点,否则也就无所谓分布式系统了,因此分区容错性也就成了分布式系统必须要解决的一个问题。所以分布式系统设计往往需要把主要精力放在如何根据自身 业务特点在一致性与可用性之前需求平衡。

3.2、Base理论

BASE理论是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。BASE理论是对CAP理论中的一致性和可用性权衡的结果,通过对互联网系统分布式实践的总结,其核心思想是在分布式系统中,即使无法做到强一致,但每个服务可以结合自身的业务特点,采用适合自己的方式使系统达到最终一致性。BASE理论中的三要素描述如下:

  • 1、基本可用

基本可用是指分布式系统在出现故障后,允许部分可用性损失,即是保证核心服务或链路是可用的。

比如:电商大促,当出现访问量陡增,为了保证系统的可用性,部分商户可能被引导到降级页面,保证大部分商家的一个可用性。

  • 2、软状态

软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体。比如电商网站上看到的商品剩余数量,评论数据,点赞数等;

  • 3、最终一致性

最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

总的来说,BASE理论面向的是大型高可用可扩展的分布式系统,和传统的事物 ACID 特性是相反的,它完全不同于 ACID 的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。但是在分布式系统的场景中,不同的业务单元对数据的一致性要求是不同的,因此在架构设计中,ACID与BASE理论往往是结合一起考虑的。

3.3、两阶段提交协议

在所有关于分布式事务的讲解文章中,都不可避免的要提到两阶段提交,该协议是使用最为广泛的协议,很多分布式事务处理方式都是基于该协议,或以该协议为基础再结合业务操作优化实现。确切的说,该协议主要用于保证分布式事务的原子性,即在分布式事务下的所有操作要么全部成功,要么全部不成功。所谓两阶段,可以分为:第一阶段:准备阶段,第二阶段:提交阶段。

角色职责:

事务管理器:负责发起和协调整个分布式事务,推进分布式事务流程,保证分布式达系统到一致的状态;

资源管理器:负责预留资源,提供提交或取消操作,协助事务管理器完成一致性保证;

img

1.准备阶段

准备阶段上事务协调者(事务管理器)给每个事务参与者(资源管理器)发送“准备”指令,每个参与者根据指令准备资源(如:锁定资源),如果准备成功,就返回事务协调者准备完成,如果准备失败,就返回处理失败。如果准备成功那么整个事务就达到了一种“完事具备,只欠东风”的状态,进入事务的第二阶段;

2.提交阶段

如果协调者收到了参与者在准备阶段的返回结果,如果失败或超时,直接给参与者发送回滚指令;否则,发送提交指令;参与者根据协调者发送的指令,执行提交或回滚操作,释放所有事务处理过程中的资源;

将事务划分为两个阶段的目的很明确,就是在准备阶段需要完成几乎所有正式提交工作,这样,最后提交提交的动作就是一个耗时极少的一次操作,这种操作在分布式环境中失败率就会大大降低,也就是所谓的“网络通信的危险期”很短,从而确保了分布式事务的成功率,这也是分布式事务的关键所在。

以上描述都是两阶段提交的一种理想状态,那么接下来我们看一下两阶段提交有哪些问题,请看如下分析:

场景一:准备阶段失败(业务一阶段)

img

如上图描述,在业务的第一阶段,在向资源管理器2发布准备命令时,出现了准备资源失败的情况,那么就需要在第二阶段时候,想资源管理器1与资源管理器2发起回滚操作。在此时有一些集中场景需要考虑:

1、如果在资源管理器1发起准备操作并获取返回结果后,再向资源管理器2发起准备操作,此时资源管理器起2一直不返回,阻塞在此处,那么整个业务流程就无法向后推进,必须等待返回后才能进而业务的二阶段,也是说在处理时存在着阻塞问题;

2、如果在事务管理器获取了资源管理器1与资源管理器2的准备就绪的逻辑后,在发起二阶段开始前,如果资源管理器宕机了,整个业务就无法继续推进,那么这里事务管理器TM就存在着单点问题。

场景二:提交阶段失败(业务二阶段)

img

如上图描述,在业务的第二阶段,在向资源管理器2发起提交时,会出现如下两种情况:

1、提交命令发出后,事务管理器宕机,整个事务状态无法知道是否完成,该问题再次说明事务管理器是单点的,无法保证业务;

2、提交命令发给资源管理器1,并成功提交,再发给资源管理器2后,由于网络问题对事务管理器2一直提交不成功,那么此时在整个分布式系统中,就存在了数据不一致(资源管理器1已结提交,资源管理器2无法提交);

综上所述,两阶段提交主要存在如下问题:

1、协调者单点问题:如上描述,一旦事务管理器宕机,整个事务的状态无法保证,分布式事务无法推进;

2、同步阻塞问题:在准备就绪后,如果参与事务的其他业务一直无法获取结果,那么就会导致资源无法释放,一直阻塞;

3、数据一致性问题:如上在场景二中描述,如果资源管理器1提交了,再提交资源管理器2时出现网络超时,那么就会导致数据不一致;

说明一下,三阶段提交就是在两阶段提交的第二阶段中加入了超时机制与自动提交,但是本质上还是没有解决一致性的问题,故而在此不在赘述。

4、分布式事务解决方案

4.1、定期校对模型

img

实现方式:

1.主动业务方在业务处理完成后,同步消息的方式将结果发送给业务被动方,消息可能存在丢失的情况;

2.被动业务方在获取了主动业务方的消息后,推进业务;

3.被动业务方定时查询主动业务方处理结果,恢复由于消息丢失导致的无法推进的业务;

约束条件:

被动业务方的处理结果不影响主动业务方处理结果;

构建成本:

需要构建定期校对模块,补偿业务;

适用范围:

1.对业务最终一致性时间敏感度较低的业务;

2.较为适合跨企业的业务活动;

3.较为适合非可靠消息或消息存在丢失的业务活动;

使用业务场景:

\1. 跨企业业务活动,数据报表对账;如:支付宝与银行交易对账;

2.下层系统通过异步化回执上层系统的架构中,上层系统通过定期校对进行数据恢复;如:上层系统充值订单,下层充值支付系统,在支付系统异步反馈充值结果的场景。

4.2 可靠消息模型

4.2.1、本地消息表模型

img

实现方式:

1.业务活动主动方,通过业务活动本地事务,记录消息信息到业务活动本地数据库中,保证操作业务数据与消息表信息在本地事务一致;

2.业务活动处理完成后,通过可靠消息系统将消息发送给业务的被动方;

3.在消息发送完成后,删除业务活动本地数据库中的消息信息;

4.消息恢复系统定期找到未成功发送的消息,交给实时消息服务补发送;

5.业务活动被动方获取消息后,处理业务;

约束条件:

1.被动业务方的处理结果不影响主动业务方处理结果;

2.被动方消息处理需要支持幂等;

构建成本:

1.可靠消息系统(即:消息投递到消息中间件后,不能丢失且消息必须送达消费者);

2.消息恢复系统;

适用范围:

1.对最终一致性实时性要求较高的场景;

2.降低业务被动方的实现成本;

使用业务场景:

1.业务量不是特别大的场景(消息表信息要写入本地业务数据库,如果交易量大会导致本地消息表信息过大,占用业务数据库储存),适合通过异步消息方式进行解耦,并使用可靠MQ保障最终一致性的场景;如:消费送积分,消费送券;

4.2.2、事务性消息中间件模型

img

实现方式:

1.主动方在业务处理服务在提交事务前,向实时消息服务发送消息,实时消息服务只记录消息,不发送消息;

2.在主动方业务处理服务完成事务后,向实时消息系统发送确认消息,只有收到了确定消息后,实时消息系统才发送消息;

3.主动方业务处理失败后,向实时消息系统发送取消发送;

4.消息状态确认系统定期找到未确认发送或取消的消息,向业务系统确认消息的状态,业务系统需要根据消息体信息确认消息是否有效,是发送还是取消;

构建成本:

1.一次消息发送需要两次请求;

2.业务系统需要实现消息状态回查接口;

优点:

1.消息系统消息独立存储,独立伸缩;

2.主动方实现分布式事务逻辑简单,更加关注业务;

缺点:

1.实现分布式事务消息中间件成本高,技术难度大;

适用范围:

1.对最终一致性实时性要求加高的场景;

2.降低业务系统的实现成本,一致性的保证交由中间件保证;

适用场景

1.业务量较大的场景,通过分布式中间件进行补偿操作,满足最终一致性即可。

2.适合将大事务拆分为多个小事务加异步的方式,保证最终一致性的场景。

4.3、非可靠消息模型

img

实现方式:

1.业务活动主动方,通过业务活动本地事务,记录消息信息到业务活动本地数据库中;

2.业务活动处理完成后,通过非可靠消息系统将消息发送给业务的被动方(注意:消息存在丢失);

3.消息校对服务定期查询被动方服务处理结果,并将未处理成功的消息重新投递给消息系统进行补发送;

4.业务活动被动方获取消息后,处理业务;

约束条件:

1.被动业务方的处理结果不影响主动业务方处理结果;

2.被动方消息处理需要支持幂等;

3.查询业务把业务主动方与被动方耦合在一起;

构建成本:

1.定期校对系统;

2.消息恢复系统;

适用范围:

1.对最终一致性实时性要求不高的场景;

2.降低业务处理的复杂度,可以将一个业务拆分为两个,并保证最终一致的模型;

说明:

其实采用消息系统来保证分布式事务一致的模型都是一种异步化模型,将原来一个大事务拆成了多个小事务加异步化的方式实现。

所以在分布式系统中常常可以使用该结论:大事务=小事务+异步化

4.4、TCC模型

img

实现方式:

1.一个业务活动有一个主业务活动与若干个从业务活动组成;

2.主业务活动负责发起整个业务活动,承担部分协调者的角色;

3.从业务活动负责提供TCC操作;

4.业务活动管理器负责控制业务活动的一致性,它记录业务活动操作,并在业务活动提交时确认所有的TCC型操作的confirm操作,在业务活动取消时调用所有TCC型操作的cancel操作,如果调用提交或取消接口失败,需要支持定期重试,事务达到最终一致的状态;

构建成本:

1.业务被动方需要实现TCC操作;

2.业务活动结束时,活动管理器需要调用confirm或cancel操作的成本;

3.业务活动操作日志记录的成本;

适用场景:

1.强隔离性,强一致性要求的业务活动;

2.适用于执行时间较短的业务活动;

4.5、补偿型

img

实现方式:

1.业务活动又一个主业务活动与若干从业务活动构成,一般又主业务活动发起并结束整个业务活动;

2.从业务活动需要提供补偿操作,补偿操作一般是低效正向操作业务结果;

3.业务活动管理器用于登记业务活动操作,保证业务的一致性,并在主业务活动取消时,调用从业务活动的补偿操作;

构建成本:

1.从业务活动实现补偿操作的成本;

2.由于无法补偿带来的业务成本;

适用场景:

1.弱隔离性,弱一致性要求的业务活动;

2.适合执行时间较长的业务活动,比如:工作流;

5、TCC方案说明

分布式事务模型中,在对一致性要求较高的场景下,使用最多的就是TCC模型,本小节将结合前面学习事务理论基础,结合业务,提供一套基于TCC模型的分布式事务框架的解决方案。

5.1、再探TCC

img

在之前描述了两阶段提交各个角色的职责,以及存在的主要问题,由于TCC模型的主要设计思路是来自于两阶段提交,我们就再来剖析一下TCC模型是如何巧妙的规避两阶段提交的问题,最终作为了分布式事务中“强一致”模型的不二选择。下面我们来逐一说明:

问题解决:

1.协调者单点问题:将协调者由单点,变为多点,抽象为集群;

2.同步阻塞:引入超时机制,超时后再进行补偿处理;

3.数据一致性问题:在引入补偿后,不会出现阻塞,那么数据会在一定时间后达到一致;

角色划分:

1.协调者:

在TCC模型中,协调者由两个组件担任:

a) 主业务活动:主要负责发起业务活动,登记业务操作,只参与业务一阶段,业务活动的最终状态就是分布式事务的最终状态;

b) 业务活动管理器:负责记录活动日志,推进业务活动,在业务处理出现超时后进行补偿操作,保证分布式事务达到一致的状态;

2.参与者:

a) 负责提供准备,提交,取消方法,等待主业务活动或业务活动管理器的调用;

b) 由于业务活动管理器在出现超时后,为了保证分布式事务一致性会发起重试,所以提交/取消操作接口需要支持幂等;

实现说明:

在TCC模型中,协调者主要由:主业务活动与业务活动管理器共同担任,二者协调来完成两阶段提交中协调者的工作,那么在真正的实现中,主业务活动就是某一个业务服务,所以不存在单点问题,业务活动管理器可以分布在应用服务中,也可以单独抽离出来作为一个独立的服务,这也就是在TCC模式下的两种实现策略,我把它称为“应用级业务活动管理器”和“集群式业务活动管理器”,这两种模式会对TCC模型设计提出不同的挑战,下面我们就分别来描述一下这两种实现方式。

5.2、TCC实现策略

5.2.1、应用级模式

img

在应用级模式中,承担协调者的业务活动与活动管理器都属于应用中,那么由于我们现在的服务都是多台部署,故而这两者都不是单点的,所以就不存在协调者的单点问题。同理,按照TCC设计思路,业务活动的处理结果就是整个分布式事务的处理结果,在业务处理完成后,协调者再发起提交的各种异常情况(超时,网络断开)等,我们引入补偿机制,使分布式事务达到最终一致;

该模式主要的优缺点如下:

优点:

1.分布式事务实现简单,将协调者拆解为两个主要角色,在应用中实现;

2.业务活动的注册,提交/回滚操作与业务操作在一个线程中处理,效率高;

缺点:

1.业务活动日志记录侵入业务系统数据库;

2.业务活动逻辑代码与分布式事务代码耦合在一起;

3.业务活动管理器日志扩容受到应用系统影响,扩容不便;

适用场景:

分布式事务规模不大,业务处理实时性高的场景;

5.2.2、集群模式

img

集群模式的分布式事务框架实现逻辑,在实现方式上与“分布式事务性消息中间件”的实现思路基本一直,业务活动参与完成准备阶段后,就存储业务的状态,业务处理的最终状态就是分布式事务的最终状态。存储活动记录的日志本质的目的就是为了后续的补偿做服务,原理与应用级分布式事务框架一致。

该模式具有以下优缺点:

优点:

1.分布式业务活动管理器采用集中管理,系统便于扩容;

2.业务数据与活动日志数据分离存储,业务划分清晰合理;

缺点:

1.实现难度大,一般需要基于公司层面的基础框架整合;

2.活动日志的注册,提交/回滚的协调是通过RPC实现,稳定性稍差(相对应用级在同一个JVM的线程中处理,不存在RPC调用);

适用场景:

适用业务量大,较为集中的做分布式事务处理服务(比如:做公司级的分布式事务框架)

5.3、分布式事务框架DTS

5.3.1、设计说明

分布式事务框架DTS的设计思路是基于“应用级模式”进行设计的,具体实现思路如下时序图描述:

img

  • 角色说明:

    业务发起方:发起分布式事务,参与一阶段提交,发起方执行的本地事务的最终状态,就是整个分布式事务的最终状态;

    业务参与方:分布式事务的参与者,参与系统的一阶段与二阶段,在事务发起方提交时候后,根据分布式事务的执行状态,判断执行参与者对应二阶段的提交或回滚操作;

    业务参与方代理:主要代理落库操作日志,便于在出现分布式事务异常状态下,回滚操作事务;

    角色如下图:

img

  • 表结构设计:

    business_activity:

字段 类型 是否可空 描述
id bingint(20) 主键
tx_id VARCHAR(40) 事务ID
state CHAR(1) 状态信息
create_time datetime 创建时间
update_time datetime 更新时间

business_action:

字段 类型 是否可空 描述
id bingint(20) 主键
action_id VARCHAR(40) action业务ID
tx_id VARCHAR(40) 事务ID
name VARCHAR(60) 名称
state CHAR(1) 状态信息
create_time datetime 创建时间
update_time datetime 更新时间
context VARCHAR(4000) 业务上下文信息

业务状态机:

img

5.3.2、事务状态分析

按照业务流程说明各个阶段分布式事务状态,具体分析如下:

1).整个分布式事务都成功:

img

2).分布式事务失败:

img

3). 一阶段提交超时:

img

4). 二阶段提交失败

img

6、参考

分布式系统的CAP理论

微服务数据一致性的演进:SAGA,CQRS,Event Sourcing的由来和局限

https://app.yinxiang.com/fx/10fabe26-18b2-4002-9f65-cd5faf49499f


分布式事务:

本地事务:(ACID)

指传统的单机数据库事务,必须具备ACID。

原子性和持久性,靠的是undo和redo的日志。

results matching ""

    No results matching ""