分布式事务

本地事务

指的是传统的单击数据库事务。必须具备ACID原则。
A:原子性。
根据定义,原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做。即要么转账成功,要么转账失败,是不存在中间的状态!
如果无法保证原子性会怎么样?
OK,就会出现数据不一致的情形,A账户减去50元,而B账户增加50元操作失败。系统将无故丢失50元~

C:一致性。根据定义,一致性是指事务执行前后,数据处于一种合法的状态,这种状态是语义上的而不是语法上的。
那什么是合法的数据状态呢?
oK,这个状态是满足预定的约束就叫做合法的状态,再通俗一点,这状态是由你自己来定义的。满足这个状态,数据就是一致的,不满足这个状态,数据就是不一致的!
如果无法保证一致性会怎么样?
例一:A账户有200元,转账300元出去,此时A账户余额为-100元。你自然就发现了此时数据是不一致的,为什么呢?因为你定义了一个状态,余额这列必须大于0。
例二:A账户200元,转账50元给B账户,A账户的钱扣了,但是B账户因为各种意外,余额并没有增加。你也知道此时数据是不一致的,为什么呢?因为你定义了一个状态,要求A+B的余额必须不变。
I:隔离性。四种隔离级别
读未提交:能够读到其他事务未提交的数据
读可提交:只能读到其他事务已提交的数据,未提交的读不到
重复度:在当前事务中,不管其他事务是否提交,当前事务内任何时间段读到的数据都是一致的。
串行:所有事务排队,事务不会相互影响
D:持久性。根据定义,持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
如果无法保证持久性会怎么样?
在Mysql中,为了解决CPU和磁盘速度不一致问题,Mysql是将磁盘上的数据加载到内存,对内存进行操作,然后再回写磁盘。好,假设此时宕机了,在内存中修改的数据全部丢失了,持久性就无法保证。
设想一下,系统提示你转账成功。但是你发现金额没有发生任何改变,此时数据出现了不合法的数据状态,我们将这种状态认为是数据不一致的情形。

原子性、隔离性、持久性的目的是为了事务的一致性。数据库本身能保证原子性、隔离性和持久性,一致性需要数据库的使用人员保证。
隔离性是数据通过隔离级别来控制,那么原子性和持久性是通过什么控制呢?
答案是undolog  和redolog。

undo log:
保存操作之前的数据,一旦发生故障,根据这个日志可以回复到数据最初的值。
假设有A、B两个数据,值分别为1,2。
A. 事务开始.
B. 记录A=1到undo log.
C. 修改A=3.
D. 记录B=2到undo log.
E. 修改B=4.
F. 将undo log写到磁盘。
G. 将数据写到磁盘。
H. 事务提交

redo log:
保存修改之后的数据,redolog写入磁盘有两个时机:缓存区满了或者事务提交
 A. 事务开始.
 B. 记录A=1到undo log buffer.
 C. 修改A=3.
 D. 记录A=3到redo log buffer.
 E. 记录B=2到undo log buffer.
 F. 修改B=4.
 G. 记录B=4到redo log buffer.
 H. 将undo log写入磁盘
 I. 将redo log写入磁盘
 J. 事务提交
 
最后总结一下:

- undo log 记录更新前数据,用于保证事务原子性
- redo log 记录更新后数据,用于保证事务的持久性
- redo log 有自己的内存buffer,先写入到buffer,事务提交时写入磁盘
- redo log 持久化之后,意味着事务是**可提交**的

分布式事务

分布式事务,就是指不是在单个服务或单个数据库架构下,产生的事务:
分布式事务产生的原因:
- 跨数据源的分布式事务
- 跨服务的分布式事务
- 综合情况

解决分布式事务的指导思想

CPA定理和BASE理论。
1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标。
Consistency(一致性)
Availability(可用性)
Partition tolerance (分区容错性)
分区容错:
大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如,一台服务器放在上海,另一台服务器放在北京,这就是两个区,它们之间可能因网络问题无法通信。
一致性:写操作之后的读操作,必须返回该值。举例来说,某条记录是 v0,用户向 G1 发起一个写操作,将其改为 v1。
可用性:只要收到用户的请求,服务器就必须给出回应(对和错不论)

解决分布式事务的方案

1、分阶段提交。代表:两阶段提交DTP模型和XA协议。
缺点:单点故障,阻塞。
使用场景:对事务有强一致性要求,对事务执行效率不敏感,并且不希望有太多代码侵入
2、TCC。TCC模式可以解决2PC中的资源锁定和阻塞问题,减少资源锁定时间。
- Try:资源的检测和预留;
- Confirm:执行的业务操作提交;要求 Try 成功 Confirm 一定要能成功;
- Cancel:预留资源释放。
- 优势
TCC执行的每一个阶段都会提交本地事务并释放锁,并不需要等待其它事务的执行结果。而如果其它事务执行失败,最后不是回滚,而是执行补偿操作。这样就避免了资源的长期锁定和阻塞等待,执行效率比较高,属于性能比较好的分布式事务方式。
- 缺点
- 代码侵入:需要人为编写代码实现try、confirm、cancel,代码侵入较多
- 开发成本高:一个业务需要拆分成3个步骤,分别编写业务实现,业务编写比较复杂
- 安全性考虑:cancel动作如果执行失败,资源就无法释放,需要引入重试机制,而重试可能导致重复执行,还要考虑重试时的幂等问题
3、可靠性消息。这种实现方式的思路,其实是源于ebay,其基本的设计思想是将远程分布式事务拆分成一系列的本地事务。
代表:rocketmq,rabbitmq。
**优点:**
- 与tcc相比,实现方式较为简单,开发成本低。
**缺点:**
- 数据一致性完全依赖于消息服务,因此消息服务必须是可靠的。
- 需要处理被动业务方的幂等问题
- 被动业务失败不会导致主动业务的回滚,而是重试被动的业务
- **事务业务与消息发送业务耦合**、业务数据与消息表要在一起
4、seata 的at模式。AT 模式的一阶段、二阶段提交和回滚均由 Seata 框架自动生成,用户只需编写“业务 SQL”,便能轻松接入分布式事务,AT 模式是一种对业务无任何侵入的分布式事务解决方案
优点:
- 与2PC相比:每个分支事务都是独立提交,不互相等待,减少了资源锁定和阻塞时间
- 与TCC相比:二阶段的执行操作全部自动化生成,无代码侵入,开发成本低
缺点:
- 与TCC相比,需要动态生成二阶段的反向补偿操作,执行性能略低于TCC
5、saga 解决长事务
### 优势:
- 一阶段提交本地事务,无锁,高性能
- 事件驱动架构,参与者可异步执行,高吞吐
- 补偿服务易于实现
### 缺点:
- 不保证隔离性
posted @ 2022-04-26 23:10  于贰哥  阅读(77)  评论(0编辑  收藏  举报