前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud进阶(5)–Seata分布式事务

SpringCloud进阶(5)–Seata分布式事务

作者头像
摸鱼的G
发布2024-02-07 08:13:01
600
发布2024-02-07 08:13:01
举报
文章被收录于专栏:火属性小虫火属性小虫

SpringCloud进阶(5)–Seata分布式事务

在分布式环境下,很多时候我们也需要事务的使用,如购入下单,我们可能需要经过库存服务、订单服务、用户账户服务多个步骤,如果没有事务加持,很有可能会出错。因此我们需要使用分布式事务组件–Seata

我们去实现一个图书管理系统要求:

  • 每个用户最多只能同时借阅两本不同的书
  • 图书馆中所有书都有3本
  • 用户结束流程 先调用图书服务书籍-1 -> 添加借阅记录 -> 调用用户服务用户可借阅数量-1

我们正常去实现这个操作,当用户去借阅第三本书时,会报错(借阅上限),但此时因为先调用了数据服务,图书数量已经-1,我们希望中途出现异常后,之前的操作全部回滚

而这里由于是在另一个服务中进行的数据库操作,所以传统的@Transactional注解无效,这时就得借助Seata提供分布式事务了。

分布式事务解决方案

1. XA分布式事务协议 – 2PC(两阶段提交实现)

这里的PC指的是Prepare和Commit,也就是说它分为两个阶段,一个准备一个提交。整个过程中的参与者一共有两个角色,一个是事务的执行者,一个是事务的协调者,整个事务的运作都需要依靠协调者来维持。

在准备和提交阶段,会进行:

  1. 准备阶段: 一个分布式事务是由协调者开启的,首先协调者会向所有事务执行者发送事务内容,等待所有事务执行者答复。 各个事务执行者开始执行事务操作,但是不进行提交,并将undo和redo信息记录到事务日志 如果事务执行者执行事务成功,那么告诉协调者成功,否则告诉协调者失败,不能提交事务。
  2. 提交阶段: 当所有执行者都反馈完成后,协调者会检查各个执行者的反馈内容,如果所有的执行者都返回成功,那么就会告诉所有的执行者可以提交事务了,最后在释放锁资源。 如果至少有一个执行者返回失败或者超时,那么所有的执行者都会回滚,分布式事务执行失败。

这个方式比较简单,但也存在几个问题:

  • 事务协调者是非常核心的角色,一旦出现问题,将导致分布式事务不能正常运行。
  • 如果提交阶段发送网络问题,导致某些事务执行者没有收到协调者的执行命令,将导致某些执行者提交,某些执行者没提交。

2.XA分布式事务协议-3PC(三阶段提交实现)

三阶段提交是在二阶段提交的基础上进行改进,主要是加入了超时机制,同时在协调者和执行者中都加入了超时机制。

三个阶段分别是:

  1. CanCommit阶段 协调者向执行者发送CanCommit请求,询问是否可以执行事务提交操作,然后开始等待执行者的响应。 执行者接受到请求后,正常情况下,如果器自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态,否则返回No
  2. PreCommit阶段 协调者根据执行者的反应情况来决定是否可以进入第二阶段事务。 如果所有执行者都返回Yes,则协调者向所有执行者发送PreCommit请求,并进入Prepared阶段,执行者收到请求后,会执行事务操作,并将undo和redo信息记录到事务日志中,如果成功执行则返回成功响应。 如果所有的执行者至少有一个返回NO,则协调者向所有执行者发送abort请求,所有执行者在收到请求或是超过一段时间没有收到任何请求时,会中断事务。
  3. DoCommit阶段 该阶段进行真正的的事务提交。 协调者接收到所有执行者发送的成功响应,那么他将从PreCommit状态进入到DoCommit状态,并向所有执行者发送doCommit请求,执行者接收到doCommit请求之后,开始执行事务提交,并在完成事务提交之后释放所有事务资源,并最后向协调者发送确认响应,协调者接收到所有执行者的确认响应之后,完成事务(如果因为网络问题导致执行者没有收到doCommit请求,执行者会在超时之后直接提交事务,虽然执行者只是猜测协调者返回的是doCommit请求,但是因为前面的两个流程都正常执行,所以能够在一定程度上认为本次事务是成功的,因此会直接提交) 协调者没有接收至少一个执行者发送的成功响应(也可能是响应超时),那么就会执行中断事务,协调者会向所有执行者发送abort请求,执行者接收到abort请求之后,利用其在PreCommit阶段记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源,执行者完成事务回滚之后,向协调者发送确认消息, 协调者接收到参与者反馈的确认消息之后,执行事务的中断。

三段式在两段式的基础上作出改动,但也有缺点:

  • 3PC在2PC的第一阶段和第二阶段中插入一个准备阶段,保证了在最后提交阶段之前各参与节点的状态是一致的。
  • 一旦参与者无法及时收到来自协调者的信息之后,会默认执行Commit,这样就不会因为协调者单方面的故障导致全局出现问题。
  • 但是我们知道,实际上超时之后的Commit决策本质上就是一个赌注罢了,如果此时协调者发送的是abort请求但是超时未接收,那么就会直接导致数据一致性问题。

3.TCC(补偿事务)

补偿事务TCC就是Try、Confirm、Cancel,它对业务有侵入性,一共分为三个阶段。

  1. Try阶段 比如我们需要在借书时,将书籍的库存-1,并且用户的借阅量也-1,但是这个操作,除了直接对库存和借阅量进行修改之外,还需要将减去的值,单独存放到冻结表中,但是此时不会创建借阅信息,也就是说只是预先把关键的东西给处理了,预留业务资源出来。
  2. Confirm阶段 如果Try执行成功无误,那么就进入到Confirm阶段,接着之前,我们就该创建借阅信息了,只能使用Try阶段预留的业务资源,如果创建成功,那么就对Try阶段冻结的值,进行解冻,整个流程就完成了。当然,如果失败了,那么进入到Cancel阶段。
  3. Cancel阶段 把冻结的东西还给人家,因为整个借阅操作压根就没成功。就像你付了款买了东西但是网络问题,导致交易失败,钱不可能不还给你吧。

跟XA协议相比,TCC就没有协调者这一角色的参与了,而是自主通过上一阶段的执行情况来确保正常,充分利用了集群的优势,性能也是有很大的提升。但是缺点也很明显,它与业务具有一定的关联性,需要开发者去编写更多的补偿代码,同时并不一定所有的业务流程都适用于这种形式。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringCloud进阶(5)–Seata分布式事务
  • 分布式事务解决方案
    • 1. XA分布式事务协议 – 2PC(两阶段提交实现)
      • 2.XA分布式事务协议-3PC(三阶段提交实现)
        • 3.TCC(补偿事务)
        相关产品与服务
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档