文章目录
随着系统业务的不断提升,很多公司的后端已经开始了分布式集群的方案。当系统转为分布式系统时,原先的单机数据库事务已经不再满足现有业务,所以分布式事务解决方案也出现了。
1. 什么是事务
事务(Transaction)是访问/更新数据库中各种数据项的一个程序执行单元。
举个生活中的例子就是买东西,付钱和交货必须全部成功才可以完成交易,买卖任何一方出现问题都无法完成交易
1.1 本地事务
在计算机系统中,一般利用关系型数据库本身的事务特性来做事务控制。一般我们程序只操作单一数据库,这种情况称为本地事务。
1.2 分布式事务
典型的分布式事务场景:
- 跨库访问
- 服务化多应用访问
2. 分布式事务基础理论
2.1 CAP理论
2000年7月,加州大学伯克利分校的Eric Brewer教授在ACM PODC会议上提出CAP猜想。2年后,麻省理工学院的Seth Gilbert和Nancy Lynch从理论上证明了CAP。之后,CAP理论正式成为分布式计算领域的公认定理。
- 一致性(Consistency):客户端每次读取,服务器返回最新数据或响应错误。这里强调重点是数据强一致性,另可返回失败,也不能返回不正确的数据;
- 可用性(Availability):客户端请求都能得到数据响应,不会出现响应错误。可用性强调的是返回不出错,客户端任何时候访问都能成功获取到数据,但不能保证数据是最新的;
- 分区容错性/分区容忍性(Partition tolerance):分布式系统节点部署在不同子网,这就是网络分区。分布式系统需要在网络问题导致节点间通信故障或任何网络分区出现故障时,仍能对外提供服务,除非是整个网络环境都发生了故障。
一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容忍性(Partition tolerance)这三项中的两项。
举个例子来看一般为什么只能CP或AP:
数据库主从同步:
C为了保证客户端不会读到旧数据,需要对从库加锁,这可能会造成访问超时,而A为了可用性不可对从库加锁;主库和从库之间在客户端请求时同步未完成或同步出现问题导致同步失败,这时C不能将旧数据返回给客户端,而A会返回旧数据或默认数据。
2.2 BASE理论
BASE理论是对CAP理论的延伸,核心思想是即使无法做到强一致性(Strong Consistency,CAP的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consitency)。
BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的缩写。
-
基本可用(Basically
Available):指分布式系统在出现不可预知故障的时候,允许损失部分可用性。如付费系统出了问题,正常登录浏览还可以正常使用。 -
软状态( Soft State):指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性。如转账时增加转帐中状态。
-
最终一致( Eventual
Consistency):强调的是所有的数据更新操作,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。如转账中最终变为转帐成功或失败。
3 分布式事务解决方案
3.1 2PC
2PC实际上就是引入了分布式的事务管理器,所有参与者与事务管理器进行沟通,决定事物的提交和回滚,主要包含两个阶段:
- 1阶段,TM调用xa_prepare()函数向各RM发送事务预处理请求,之后各RM执行锁定本地事务资源但不会真正提交,而是向TM报告是否能够处理;
- 2阶段,如果所有RM返回给TM的预处理结果都为yes,则TM调用xa_commit()函数向各RM发送提交请求,只要有一个或多个RM返回no或反馈超时,则TM调用xa_rollback()函数要求各RM回滚事务。
缺点:
同步阻塞,Prepare阶段锁定资源,性能影响大;
单点故障,
TM故障,RM资源锁定无法释放;
RM故障,TM无法收到反馈,陷入阻塞;
数据不一致,可能有部分RM没有收到commit/rollback请求,导致数据不一致。
3.2 3PC
三阶段提交(3PC),是二阶段提交(2PC)的改进版本。与两阶段提交不同的是,三阶段提交有两个改动点:
- 引入超时机制。同时在协调者和参与者中都引入超时机制。
- 在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。也就是说,除了引入超时机制之外,3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。
3.3 可靠消息最终一致性
本地业务执行结果应和消息发送结果一致,如果本地业务执行成功,则消息一定要成功发送出去(一般发到消息中间件mq中)。
伪代码演示发送投递的不可靠性:
Start transaction
Send MQ;
Operate local DB;
Commit transaction
可能发送MQ成功,本地执行失败,MQ发送无法回滚
Start transaction
Operate local DB;
Send MQ;
Commit transaction
网络超时导致本地事务回滚,但其实mq消息已经成功发送给参与方。
3.4 本地消息表
本地消息表的方式是将分布式事务转换为本地事务。当本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证在对这两个表的操作满足事务特性,并且使用了消息队列来保证最终一致性。
- 在分布式事务操作的一方完成写业务数据的操作之后向本地消息表发送一个消息,本地事务能保证这个消息一定会被写入本地消息表中。
- 之后将本地消息表中的消息转发到 Kafka 等消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发。
- 在分布式事务操作的另一方从消息队列中读取一个消息,并执行消息中的操作。
3.5 RocketMQ事务消息方案
Rocket MQ 4.3之后的版本正式支持事务消息。
RocketMQ支持事务消息的方式是类似于二阶段提交的方案。其思路大致为:
第一阶段Prepared消息,会拿到消息的地址。
第二阶段执行本地事务,第三阶段通过第一阶段拿到的地址去访问消息,并修改状态。
也就是说在业务方法内要想消息队列提交两次请求,一次发送消息和一次确认消息。如果确认消息发送失败了RocketMQ会定期扫描消息集群中的事务消息,这时候发现了Prepared消息,它会向消息发送者确认,所以生产方需要实现一个check接口,RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样就保证了消息发送与本地事务同时成功或同时失败。
3.6 最大努力通知
最⼤努⼒通知⽅案的⽬标,就是发起通知⽅通过⼀定的机制,最⼤努⼒将业务处理结果通知到接收⽅。
最⼤努⼒通知事务主要⽤于外部系统,因为外部的⽹络环境更加复杂和不可信,所以只能尽最⼤努⼒去通知实现数据最终⼀致性,⽐如充值平台与运营商、⽀付对接、商户通知等等跨平台、跨企业的系统间业务交互场景。