分布式事务详解

1.什么是事务?

事务(Transaction)是由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元(Unit),这些操作要么都执行,要么都不执行。

 

事务具备四个特征:原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability),简称ACID特性。

  1. 原子性(atomicity):原子性是指事务是一个不可分割的工作单元,事务中的操作要么都执行,要么都不执行。

  2. 一致性(consistency):事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。

  3. 隔离性(isolation):隔离性是指当多个用户并发访问数据库时,数据库为每个用户开启的事务,不能被其余事务的操做所干扰,多个并发事务之间要相互隔离。

  4. 持久性(durability):持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即使是在数据库系统遇到故障的状况下也不会丢失提交事务的操做。

1.1本地事务

大多数场景下,我们的应用都只需要操作单一的数据库,这种情况下的事务称之为本地事务(Local Transaction),一个数据库范围内事务管理。

1.2分布式事务

完成一个业务功能需要调用多个微服务,操作多个数据库此时需要分布式事务来保证多个资源服务器的数据操作要么全部成功,要么全部失败,即保证不同资源服务器的数据一致性。

分布式事务用在分布式系统中,保证不同节点之间的数据一致性。

1.3分布式事务两大理论依据:CAP定律 BASE理论

1.3.1 CAP定律

这个定理的内容是指的是在一个分布式系统中:Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼

(1)分区容错性(Partition tolerance)

以实际效果而言,分区相当于对通信的时限要求系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

大多数分布式系统都分布在多个子网络,每个子网络叫做一个分区(partition),分区容错的意思就是区间通信可能失败。比如:一台服务器放在北京,一台服务器放在深圳,这就是两个区,它们之间可能无法通信。一般来说,分区容错是无法避免的,因此可以认为CAP定理中P总是成立的

(2)一致性(Consistency)

在分布式系统中的所有数据备份,在同一时刻具有相同样的值,等同于所有节点访问同一份最新的数据副本

 

一致性(Consistency)是指写操作之后的读操作,必须返回该值。例如:客户端(client)向G1发起一个写操作,将v0改为v1,接下来用户的读操作就会得到v1,这叫一致性。但是,用户有可能想G2发起读操作,由于G2的值没有发生变化,因此返回的值仍然是v0。G1和G2读操作的结果不一致,不满足一致性。

 

为了同步G2的值,在G1写操作的时候,让G1向G2发送一条同步消息,把G2的值从v0改为v1,当用户向G2发起读操作时,也能得到v1值。

(3)可用性(Availability)

在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求(对数据更新具备高可用性)。

可用性(availability)指只要接收到用户请求时,服务器就必须给出响应。客户端(client)向G1或G2发起读操作,不管是哪一台服务器,只要接收到请求,就必须返回对应的值给到用户,不管是v0还是v1,否则就不满足可用性。

(4)一致性(consistency)与可用性(Availability)

一致性和可用性为什么不能同时成立?答案很简单,因为网络故障可能导致服务间通信失败(即出现分区容错)。

如果保证G2的一致性,那么G1必须在写操作时,锁定G2的读操作和写操作。只有在数据同步完成之后,才能重新开放读写操作。G2锁定期间,不能进行读写,没有可用性。如果保证G2的可用性,则G1写操作期间,不能锁定G2,所以一致性不成立。

综上可知,G2无法同时满足一致性和可用性。系统设计时只能选择一个目标,如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那么就无法做到一致性。

分布式系统中,一般可用性高于一致性!

1.3.2 BASE理论

BASE是Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的缩写。

BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结, 是基于CAP定理逐步演化而来的

BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性

(1)基本可用(Basically Available

    基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性,比如:

  1. 响应时间上的损失。正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒

  2. 系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。

(2)软状态(Soft state

    软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。例如:订单的“支付中”、“运行中”等状态,待数据最终一致后状态改为“成功状态”。

(3)最终一致性(Eventually consistent

    最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。例如:订单的“支付中”状态,最终会变成“支付成功”或者“支付失败”,是订单状态与实际交易结果达成一致,但是需要一定的时间延迟、等待。

 

2.柔性事务与刚性事务

  1. 刚性事务:严格遵守ACID原则的事务,例如单机环境下的数据库事务。

  2. 柔性事务:是指遵循BASE理论的事务,通常用在分布式环境中,常见的实现方式有

    1. 两阶段提交(2PC)

    2. TCC补偿型提交

    3. 基于消息的异步确保型

    4. 最大努力通知型

通常本地事务采用刚性事务,分布式事务使用柔性事务。

2.1两阶段提交(2PC:Two Phase Commit)

两阶段提交(Two Phase Commit)具有强一致性是分布式事务的一种典型实现。最具代表性的有Oracle Tuxedo系统提出的XA分布式事务协议,JTA等XA协议中有两个角色:事务协调者和事务参与者

1.第一阶段

作为事务协调者的节点首先会所有的参与者发送Prepare请求,在接收到Prepare请求之后,每个事务参与者节点会各自执行与事务有关的数据更新,写入Undo Log和Redo Log如果参与者执行成功,暂时不提交事务,而是向事务协调者节点返回“完成”消息当事务协调者接收到所有参与者返回的消息后,整个分布式事务进入第二阶段。

2.第二阶段

如果事务协调者收到所有参与者的返回结果都是正向返回那么它将会向所有事务参与者发出commit请求接收到commit请求之后,事务参与者节点会各自进行本地事务提交,并释放锁资源。当本地事务完成提交后,将会向事务协调者返回“完成”消息。当事务协调者接收到所有事务参与者的“完成”反馈信息之后,整个分布式事务完成

如果某个事务参与者反馈“失败”消息,说明该节点的本地事务执行不成功,必须回滚。于是在第二阶段,事务协调者节点将会向所有参与者节点发送Abort请求,事务参与者接收到Abort请求之后,各个事务参与者节点需要在本地进行事务回滚操作,回滚操作依照Undo Log来进行。

 

两阶段提交(2PC)实现框架:开源软件atomikos(https://www.atomikos.com/Main/WebHome)

两阶段提交(2PC)不足:

  1. 性能问题XA协议遵循强一致性在事务执行过程中,各个节点占用着数据库资源只有当所有参与者节点准备完毕之后,事务协调者才会通知提交,参与者提交后才会释放资源

  2. 事务协调者单点故障问题事务协调者是这个XA模型的核心,一但事务协调者节点挂掉事务参与者接收不到事务提交或回滚通知,则事务参与者会一直处于中间状态无法完成事务

  3. 消息丢失导致不一致问题:XA协议的第二阶段,如果发生局部网络问题,一部分事务参与者接收到提交消息,另一部分事务参与者没有接收到提交消息,那么就会导致节点间的数据不一致。

2.2 TCC(Try-Confirm-Cancle TCC两阶段补偿性方案)

TCC事务的出现是为了解决应用拆分带来的跨应用业务操作原子性问题每个事务参与者需要实现3个操作:Try、Confirm和Cancel,3个操作对应两个阶段Try方法对应第一阶段的资源检测和预留阶段,Confirm和Cancel对应第二阶段的提交和回滚事务开启的时候,由发起方去触发第一阶段的方法,然后根据各个参与者返回状态决定第二阶段是调用Confirm还是Cancel方法。

常见的一个下单扣减库存问题:

TCC又被称为两阶段补偿事务,第一阶段try只是预留资源,第二阶段要明确的告诉服务提供者,这个资源要(confirm)还是不要(cancel),用来清除第一阶段的影响,所以叫补偿型事务。

 

Hmily:TCC两阶段补偿事务实现框架。如果出现cancel异常或者confirm异常的情况,在try阶段会保存好日志,Hmily有内置的调度线程池来进行恢复。

 

TCC使用场景:

  1. 严格一致性

  2. 执行时间短

  3. 实时性要求高

TCC缺点是什么?

TCC对代码侵入性大,每套业务逻辑都要按照try(请求资源)、confirm(操作资源)、cancel(取消资源)拆分为三个接口。

 

2.3 异步确保型

常见业务场景:转账问题,张三从支付宝转100元到余额宝,支付宝账户余额减100,余额宝账户加100。可借助消息队列完成转账。

存在问题:一致性问题。例如:

事务开始

(1)张三支付宝账户扣减100元;

(2)将(余额宝账户加100元)封装为消息,发送到消息队列;

事务结束

第一步是操作数据库,第二步是发送消息到消息队列,如何保证两者之间的一致性?

解决方案:添加一张事务表,如图所示:

此时事务内容为:

事务开始

(1)张三支付宝账户扣减100元;

(2)在事务表中插入一条记录;

事务结束

那么我们可以写一个定时任务,定时扫描事务表,将表中状态为“unfinished”的事件封装为消息,发送到消息中间件之后将其状态改为“finished”。

定时任务:

(1)定时扫描事务表,发现一条状态为“unfinished”的记录;

(2)将该条记录封装为消息,发送到消息中间件;

(3)将时间状态改为“finished”。

以上还存在一个问题:幂等性 问题

 假设程序在执行步骤(2)的时候,将消息发送到消息中间件,但是步骤(3)还未执行就程序出现异常,该条记录的状态还未改变,还是“unfinished”状态。那么下次定时任务扫描的时候还会将该记录进行封装,发送到消息中间件,导致重复消费问题因此,需要保证幂等性问题。

 解决方案:在消费者端,也维护一个带主键的表,该主键为唯一主键。如果出现重复消费时,在消费者端直接报主键冲突异常,从而保证幂等性。

 

 

 3.分布式事务常用框架选择

 3.1 GTS-分布式事务解决方案

GTS是由阿里巴巴中间件部门研发的一块分布式事务中间件,可为微服务架构中的分布式事务提供一站式解决方案。不开源。

 

GST核心优势:超强的性能,解决了事务ACID特性与高性能、高可用、低侵入不可兼得的问题。单事务分支的平均响应时间约为2ms,3台服务器组成的集群可以支持3万TPS以上的分布式请求。

  1. 应用低侵入:GTS对业务低侵入,业务代码最少只需要添加一行注解(@TxTransaction)事务声明即可。业务与事务分离,将微服务从事务回滚中解放出来,微服务关注业务本身,不再需要考虑反向接口、幂等、回滚策略等复杂问题,极大降低了服务开发的难度与工作量。

  2. 完整的解决方案:GTS支持多种主流的服务框架,包括EDAS、Dubbo、SpringCloud等。

  3. 容错能力强:GTS解决了XA事务协调器单点问题,实现真正的高可用,可以保证各种异常情况下的严格数据一致。

 3.2 TX-LCN-分布式事务解决方案

“LCN并不产生事务,只是事务的协调者”。代码完全开源。

LCN分布式事务框架的核心功能是对本地事务的协调控制,框架本身并不创建事务,只是对本地事务做协调控制。因此该框架与其他第三方框架的兼容性超强,支持所有的的关系型数据库事务,支持多数据源,支持第三方数据库框架一起使用。在使用框架的时候只需要添加分布式事务的注解即可,对业务的侵入性低。LCN框架主要是为微服务框架提供分布式事务支持,在微服务框架上做了进一步的事务机制优化,在一些负载场景上LCN事务机制要比本地事务机制的性能更好。

 

TX-LCN特点:

  1. 支持各种基于spring的db框架;

  2. 兼容SpringCloud、Dubbo、motan

  3. 使用简单,少依赖;

  4. 基于切面的强一致性事务框架;

  5. 高可用,模块可以依赖RPC做集群化,TxManager也可以做集群化;

  6. 支持本地事务和分布式事务共存;

  7. 支持事务补偿机制,增加事务补偿决策提醒;

posted @ 2022-04-10 23:07  BlogMemory  阅读(458)  评论(0编辑  收藏  举报