简介

Q:分布式事务主要解决的问题是什么?
A:分布式场景下的【原子性】

场景举例


小明买口红遇到的问题:
两个色号的口红都想要,必须保证【要么两只都买到,要么两只都不买】
如何解决?

从未听说过分布式事务概念的人也能想出办法:提前预定。

  1. 两家⻔店都预定成功:分别去购买(要求预定后一定能 成功购买)。
  2. 任意⻔店预定不成功:取消已预定成功的⻔店,不去购买。
    上述方案即是分布式事务的原型,也是核心思想==>两阶段提交

两阶段提交

工作过程

关键节点

首先,当参与者投票“是”时,它做出了肯定提交的承诺(尽管还取决于其他的参与者的投票,协调者才能做出最后决断)。
其次,协调者做出了提交(或者放弃)的决定,这个决定也是不可撤销。
正是这两个承诺确保了2PC的原子性(而单节点原子提交其实是将两个事件合二为一,写入事务日志即提交)

概念区分

两阶段提交(2PC) VS 两阶段加锁(2PL)

两阶段提交(2PC)在分布式数据库中负责原子提交
两阶段加锁(2PL)则提供可串行化隔离

协调者发生故障

2PC能够顺利完成的唯一方法是等待协调者恢复。

分布式事务分类

事务类型具体说明
数据库内部的分布式事务某些分布式数据库支持跨数据库节点的内部事务。
此时 ,所有参与节点都运行着相同的数据库软件。
例如, MySQL Cluster的NDB存储引擎就支持这样的内部分布式事务。
异构分布式事务在异构分布式事务中,存在两种或两种以上不同的参与者实现技术。
例如来自不同供应商的数据库,甚至是非数据库系统(如消息中间件)。
即使是完全不同的系统,跨系统的分布式事务业必须确保原子提交。

Q:分布式事务不用两阶段提交,行不行?

分布式事务的具体实现方案

TCC

TCC 是一种成熟的分布式事务解决方案,属于柔性补偿型,优点在于容易理解。

TCC 是服务层面的2阶段编程模型。业务需要编码实现3个接口(Try、Confirm、Cancel) :

  • Try 操作作为一阶段,主要负责资源的检查和预留。
  • Confirm/Cancel 同为二阶段
    当一阶段Try方法执行成功是调用Confirm方法提交预留的资源,执行真正的业务。
    一阶段调用失败时则调用Cancel方法,对Try方法中预留的资源进行释放。
场景举例:用户将自己【活期账户】中的30元转到【理财账户】中。
系统阶段操作
活期账户Try检查资金是否充足
若充足,资金预扣(冻结转账资金)
否则返回错误码
活期账户Confirm执行:可用资金 = 可用资金 - 转账金额
活期账户Cancel冻结资金解冻
理财账户Try检查当前账户是否可用
若可用,资金预加(预加的金额不可用于消费)
否则返回错误码
理财账户Confirm执行:可用资金 = 可用资金 + 转账金额
理财账户Cancel预加资金解除

活期账户各阶段流程如下所示【理财账户同理】:

TXC

TXC将分布式事务操作下放至JDBC层,通过SQL拦截改写实现数据正向提交和逆向补偿。

  • 优点:业务基本无需改造。
  • 缺点:只支持数据库。
    TXC是除TCC外另一种应用较为广泛的分布式事务实现。

sage

saga一般用于处理⻓活事务,即链路较⻓的事务性操作,也是通过正向操作+逆向补偿的思想实现事务,与TCC较为类似。
saga与TCC的最大不同是saga没有try阶段,即没有预留资源的操作,可用于较为简单的业务,但也由于没有预留资源,因此补偿动作也更麻烦。

举个例子:购买商品
正常流程异常回滚

Saga 的适用场景

  • 业务流程多、业务流程长
  • 无法抽象出 TCC 的 Try 阶段,但是可以很方便地实现补偿方法

Saga 相比 TCC 的优势

  • 一阶段提交本地数据库事务,无锁,高性能
  • 没有预留动作,易于改造兼容老的业务逻辑
  • 补偿服务即正向服务的“反向”,易于理解,易于实现
分布式事务不用两阶段提交,使用一阶段提交,行不行?【本质只是为了实现原子性->可中止性->方便回滚】

某些情况下可行:小明买口红的例子,不预定,直接购买,如果任意一家店缺货,则将已购买的商品退货。(很方便地实现补偿方法)。
转账逻辑不可行:比如A->B转账,一阶段提交之后,B把钱花了,此时执行回滚,B已经没钱归还给A了。


samforit
7 声望1 粉丝

« 上一篇
事务-概览