分布式事务

分布式事务

  1. 什么是事务, 有哪些特性?

事务是指 访问并可能更新数据库中各种数据项的一个【程序执行单元】。

事务有原子性、一致性、隔离性、持久性四大特性。

原子性 : 事务中包含的操作是不可分割的, 要么都做,要么都不做。

一致性: 使数据库从一个一致性状态变到另一个一致性状态。(保证多条DML语句同时成功或者同时失败。比如转账,要么转成功, 要么转失败)。

隔离性:多个事务间具有隔离,同时进行互不影响。

持久性:最终数据必须持久化到硬盘文件。

原子性 : 强调整个事务不可分割。

一致性 : 强调事务不能有中间结果(从一个正确的状态变到另一个正确的状态)。

隔离性 : 强调多个事务互不影响。

持久性 : 强调数据必须写到硬盘。

  1. 单机中是怎么保证这些特性的?

保证原子性 :  事务如果执行失败了,则需要进行回滚,怎么回滚呢?通过将与事务中结果相反的sql语句写到 undo Log 中, 再在数据中通过DB_ROW_ID记录undoLog回滚指针实现。(如果失败, 通过数据中的DB_ROW_ID字段找到undolog中对应的sql语句进行执行)。

保证隔离性: mysql隔离性与MVCC_七年蝉的博客-CSDN博客

保证持久性:需要保证数据不丢失。通过RedoLog的两段提交来实现。数据修改的过程中先将数据读取到内存中,然后在内存中进行修改,修改完最终再将数据刷到磁盘。 如果我们每次都直接将修改刷到磁盘这个过程的io操作会非常频繁,所以我们引入了一个中间缓存(redolog), 每次修改都先提交到redolog日志中(村的对磁盘的顺序读写),然后在特定时间再将数据刷到磁盘。

而binglog是mysql自带的日志文件,存的是对数据库进行修改的sql语句,我们事务中的sql语句也要保证能被记录到redolog中,所以一个事务中持久化需要做两件事, 一个是将数据写入磁盘,另一个就是将sql写入binlog中。 Redolog的二段提交就是在解决这个问题, 先将数据写到redolog中,数据的状态为未提交,再将数据写入到binlog中,最后commit的时候去修改redolog中那些未提交的数据的状态。先写,再改标记, 只有写入了binlog之后才能去改标记。

保证一致性 :一致性是最基本的属性, 其他三个属性是为了保证一致性而存在的。

  1. 分布式场景中哪些特性被破坏了?

分布式场景中原子性、隔离性、持久性、一致性。

首先一个事务被分配到多个进程中之后, 原子性就不存在了(不是一个原子操作了,不能一次回滚到之前的状态)。

其次隔离性也得不到保障(在并发的场景下readView都不一样)。

持久性每台机器都能自己分别保证。

一致性以为前两个不能保证所以也不能保证。

  1. 怎么自己去重新保证这些特性?

保证原子性 :首先每个系统都要有自己的回滚日志,然后每个事务发起的时候都要有一个统一的事务id传给下一个环节,最终根据每个环节是否成功判断事务是否需要回滚。

比如我创建一个专门协调事务的系统(事务协调器),每次需要执行一个事务的时候先通过事务协调器提交事务, 事务协调器生成一个统一的事务id,然后将这个id发生给需要调用的系统让他们执行各自的事务,他们执行的时候会根据这个id生成回滚日志,如果执行失败则进行回滚。最终每个被调用的系统都将自己事务的执行结果返回给事务协调器, 事务协调器发现所有事务都执行成功之后就表示这个事务是执行成功的,返回成功给调用者, 如果发现某一个事务执行失败,就认为这个事务执行失败了,通知其他系统根据这个事务id进行回滚,回滚完成后告诉调用方执行失败了。

这里面有很多缺陷:

  1. 阻塞,必须等所有系统都调用完了才能返回
  2. 可靠性,如果某一个系统在返回执行结果前挂了,就表示这个事务完整性缺失,你不知道他是成功还是失败,后面的操作要不要继续。

两阶段提交 :

事务协调器先询问各个系统能否执行事务。 此时各个子系统都开启了事务,然后去执行事务,不管执行成功还是失败,都不commit或者rollback,而是将结果返回给事务协调器。 事务协调器再通过所有结果来判断他们是应该rollback还是应该commit。

对于每一个事务, 事务协调器都会向所有参与者发送两次指令, 是一个异步的过程,开发复杂度上去了。而且第二次指令到达之前所有系统中的事务都是未结束状态, 也就造成了锁。

存在的问题:

  1. 单点故障问题:如果事务管理器发生故障,则整个系统将不可用。如果此时有部分参与者处于投票状态,则他们的事务一直不会结束, 他们事务中的资源也会一直被锁住。
  2. 数据不一致问题:提交阶段分成很多步,如果某一步发生问题(某些参与者最终没有commit),则会导致最终数据不一致。
  3. 同步阻塞问题:事务的参与者在第一阶段之后就开启了事务,直到第二阶段才结束事务。期间资源是被锁住的,导致系统出现严重的并发冲突。
  4. 性能降低(复杂度上升且多了很多步骤)。

三阶段提交:

相对于二阶段提交, 在执行事务之前需要先检查执行事务的条件是否满足(库存或者余额够不够等),检查通过之后第二阶段才开始执行事务(跟两段提交中的第一段类似),执行完了不提交事务,将结果反馈给事务协调器,事务协调器最终通过第二阶段所有系统的反馈决定是进行事务的提交还是回滚。 相当于多了一个预执行阶段。

二段提交 : 执行  -> 提交。

三段提交: 预执行 -> 执行 -> 提交。

一篇文章带你学习分布式事务-InfoQ

如何通过事务消息保障抢购业务的分布式一致性?-InfoQ

蚂蚁金服 《一篇文章带你学习分布式事务》总结

  • 分布式事务需要在分布式环境下首先单机的ACID特性。

初始的分布式事务是只有一个Service去调用多个DB,后面Service的业务被拆分成多个模块,就变成了多个Service去相互调用,Service调用自己的DB(复杂度更高)。

  • XA协议

如上的DTP模型中包含一个全局事务管理器(TM),和多个资源管理器(RM),全局事务管理器负责管理全局事务状态与参与的资源,协同资源一起提交或回滚。资源管理器则负责具体的资源操作。

XA协议描述了TM与RM之间的接口,允许多个资源在同一分布式事务中访问。

我可以把RM看作我的多个服务,每个服务都需要定义创建事务、提交事务的接口(这里全局的事务id怎么创建、怎么提交给每个子系统需要再看下)。我的TX是一个协调事务的中间件,每次发起事务都先通过TX,tx再生成全局的事务id,然后将这个事务id传给每个子RM,RM用这个事务id去开启事务,执行事务,执行完之后不提交事务,将执行结果再返回给TM, TM根据执行结果判断,如果所有RM的子事务都成功了,则全部提交,如果有失败的,则全部回滚。

这样可以通过第二代的提交、回滚保证事务的原子性, 以为第一阶段到第二阶段中间这段时间事务是一个未提交状态, 他们的资源都被锁着,所以每个子事务都能保证自己的隔离性(加锁时间不同,解锁时间相同,类似于数据库里面的2PL,两阶段锁,加锁阶段,只加锁,不放锁。解锁阶段,只放锁,不加锁)。每个子事务是具有一致性的,而第二阶段又能保证所有子事务的一致性,所以XA是强一致性的。

二阶段提交的好处是对业务没有入侵,坏处是第一阶段和第二阶段之间这段时间把资源锁死了。

TCC(Try 、 Confirm 、 Cancel)模型(事务补偿) :

他的核心原理是:

第一步生成事务id,用这个事务id去冻结资金需要操作的资产。

如果第一阶段检查、冻结有问题则解冻所有资产。完全没问题,则第二阶段去使用被冻结的这部分资产去消费等。

如果第二阶段某些消费存在问题,则第三阶段利用被冻结的资源将所有消费都全部回滚,并且解冻资源。如果第二阶段全部消费成功, 则直接解冻被冻结的资源,事务成功。

TCC对业务的入侵太大,但是好处在于他每个阶段都不需要加锁。

坏处在于需要大量改动业务层,是在业务层做的处理。而且中间状态也是可见的,若一致性。

如果一个微服务不能有自己的数据库,那么表示这些微服务需要被合并。

二阶段提交保证事务的强一致性,但是锁的粒度很大(一次性锁多个系统),所以性能比较差,而且存在事务调度器单点故障的问题,二阶段时网络异常导致的数据不一致问题。在并发场景下不可用。

柔性事务则牺牲了一致性,强调最终一致性(允许事务执行过程中存在数据不一致的中间状态),放弃了隔离性。每个子事务单独提交,锁的粒度非常小(只是在自己的每个阶段上锁),而且每个环节异步执行,。在高并发场景下是最佳选择(电商抢购)。

柔性事务有多种实现方式,包括 TCC、Saga、事务消息、最大努力通知等

阿里的消息队列

  1. 本地事务发起方先提交一个半事务到消息队列中
  2. 本地开始执行事务
  3. 本地事务执行失败则删除消息队列中的半事务,执行成功则将队列中的半事务修改为事务,并通知其他模块。(如果本地发起半事务之后没有去删除或者修改,消息队列会轮询确定这个事务的状态,进行删除或者修改状态)
  4. 消息队列接收到推送请求后给需要执行子事务的其他模块发消息
  5. 其他模块开启子事务,然后将结果发生给消息队列(如果不发,消息队列会一直轮询)。
  6. 消息队列根据各子事务回复的状态决定其他事务是回滚还是执行。

一定要保证消费和子事务的幂等性。

通过消息队列的方式将每个子事务的执行都变成了异步的,每个事务只需要关注自己是否成功,所以事务锁只在本事务中,时间非常短暂。

但是如果中间环节失败了怎么回滚呢? 调用方需要立即返回调用结果, 他怎么知道事务是成功还是失败呢?需要在业务层保证第一个事务成功之后其他的一定能成功?就像库存足够的情况下一定能下单成功?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值