分布式事务(三) 分布式事务解决方案

/ 分布式技术笔记数据库 / 0 条评论 / 209浏览

DTP和XA

分布式事务的解决方案之一就是两阶段提交协议(2PC:Two-Phase Commit)

1994年X/Open组织(现在的Open Group)定义了分布式事务处理的DTP模型,该模型包括这样几个角色:

在该模型中,一个分布式事务(全局事务)可以被拆分成多个本地事务,运行在不同的AP和RM上,每个本地事务的ACID很好实现,但是全局事务必须保证其中包含的每个本地事务都能成功,若有一个失败,则所有其他事务都必须回滚。 问题是本地事务处理过程中,并不知道其他事务的运行状态,因此就需要通过CRM来通知各个本地事务,同步事务执行状态。 因此各个本地事务的通信必须有一个统一的标准,否则不同数据库之间就无法通信,XA就是X/Open DTP中通信中间件和TM间联系的接口规范,定义了用于通知事务开始、提交、终止、回滚等接口,各个数据库厂商都必须实现这些接口。

2PC(两阶段提交)

参考:漫话分布式系统共识协议: 2PC/3PC篇

两阶提交协议就是根据这一思想衍生出来的,将全局事务拆分为两个阶段来执行。

正常情况

2pc

投票阶段:协调组询问各个事务参与者,是否可以执行事务。每个事务参与者执行事务,写入undo和redo log,然后反馈事务执行成功。(agree)
提交阶段:协调组发现每个参与者都可以执行事务(agree),于是向各个事务参与者发出commit指令,各个事务参与者提交事务。

异常情况

2pc

投票阶段:协调组询问各个事务参与者,是否可以执行事务。每个事务参与者执行事务,写入undo和redo log,然后反馈事务执行结果,但只要有一个参与者返回的是Disagree,就说明执行失败。 提交阶段:协调组发现每个有一个或多个参与者返回Disagree,认为执行失败,于是向各个事务参与者发出abort指令,各个事务参与者回滚事务。

缺陷

  1. 存在CRM单点故障问题 协调者挂了之后就不知道别人什么情况。 2pc

  2. 阻塞问题 在准备阶段,提交阶段,每个事务参与者都会锁定本地资源,并等待其他事务的执行结果,阻塞时间较长。

总结

  1. 面对二阶段提交的缺点,后来又演变出来了三阶段提交,但是依旧没有解决阻塞和资源锁定的问题,而且引入了新的微,因此实际场景使用较少。
  2. 2PC拥有稳定成熟的框架支持,可以保证强一致,并且对代码侵入度不高,

使用场景

3PC(三阶段提交)

TCC

TCC模式可以解决2PC中资源锁定和阻塞的问题,减少资源锁定时间。

基本原理

本质是一种补偿的机制,事务运行包括三个方法,

执行分两个阶段:

tcc

看似与两阶段提交没有什么区别,其实差距很大。

实例

假如账户A原来有100元,需要从余额扣除30元。如图: tcc

优势&缺点

优势

缺点

使用场景

可靠消息服务

源于eBay,设计思想是将远程分布式事务拆分成一系列的本地事务。

基本原理

事务分为发起者A参与者BCD

现实场景(老师给的场景,好像不恰当):

  1. 你点了一杯奶茶,付完钱。(发起者A完成)
  2. 服务员给了你一个号码牌。(参与者B)
  3. 你凭这张小票,一定能够领到一杯奶茶。(不断问服务员,重试)

本地消息表

为了避免消息发送失败或丢失,消息需要持久化到数据库。实现有简化版本和解耦合版本两种。

简化版本

mq

优点&缺点

优点

缺点

独立消息服务

通过引入独立的消息服务,完成对消息的持久化、发送、确认、失败重试等行为。 mq

RocketMQ事务消息

自带事务消息,可以保证消息的可靠性,原理就是自带了一个本地消息表。

RocketMQ-事务消息

RabbitMQ的消息确认

RabbitMQ确保消息不丢失使用的是ACK确认机制。

事务消息优点&缺点

针对缺点3,无法回滚问题。有人提出可以让事务参与者失败后,利用MQ通知消息服务,由消息服务通知其他参与者回滚,可是这是在利用MQ重新实现了2PC,又是一个轮子。没必要

Seata

官网:http://seata.io/

Seata是阿里开源的框架,支持XA,AT,TCC,SAGA四种模式。

AT模式

2019年1月份,Seata开源了AT模式。AT模式是一种无侵入的分布式事务解决方案。是对TCC或两阶段提交模型的优化,解决了TCC模式代码侵入,编码复杂等问题。

在AT模式下,用户只需要关注自己业务的"sql",用户的业务SQL作为“一阶段”,Seata框架会解析SQL自动生成事务的“二阶段”提交或回滚操作。

Seata官方文档:seata.io

at-1

乍一看和TCC协议很像,都是分两阶段提交。

一阶段

一阶段,Seata会拦截业务SQL,首先解析SQL语义,找到业务SQL要更新的业务数据,在业务数据被更新前,将其保存为before image,然后执行业务SQL,更新业务数据,在业务数据执行之后,再将其保存为after image,最后获取全局行锁,提交事务。以上所有操作都是在一个本地事务中完成,保证了一阶段的原子性。

before imageafter image类似于数据库的undo log和redo log。

at-2

二阶段提交

二阶段如果是提交的话,因为业务SQL在一阶段已经提交到数据库,所以Seata框架只需要将一阶段保存的快照数据和行锁删掉,完成数据清理即可。

二阶段回滚

回滚可直接使用before image还原业务数据,但在还原前首先要检查脏写,对比数据库当前业务数据after image,如果两份完全一致则没有脏写,可以还原;如果数据不一致,说明出现了脏写,需要人工处理。

详细架构和流程

基本概念

at-3

详细流程

优点&缺点

适用场景