Spring Cloud 微服务项目实战
姚秋辰(姚半仙)
PayPal 研发经理
15862 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 38 讲
结束语 (1讲)
Spring Cloud 微服务项目实战
15
15
1.0x
00:00/00:00
登录|注册

34 | 分布式事务:使用 Nacos+Seata 实现AT模式

你好,我是姚秋辰。
在上一节中我们已经搭建了 Seata Server,这节课我们就来动手落地一套 Seata AT 方案。Seata AT 不仅是官方最推荐的一套分布式事务解决方案,也是大多数 Seata 使用者选用的方案。AT 方案备受推崇,一个最主要的原因就在于省心。
Seata AT 可以给你带来一种“无侵入”式的编程体验,你不需要改动任何业务代码,只需要一个注解和少量的配置信息,就可以实现分布式事务。这似乎听上去有那么点玄幻,如果一个分布式方案既不依赖 XA 协议的长事务方案,又不依赖代码补偿逻辑,那碰到 Rollback 的时候它怎么知道该回滚哪些内容呢?
下面我就通过一个实际的业务模型,带你了解一下 AT 方案的底层原理。

Seata AT 底层原理

我们以“删除券模板”作为落地案例,它需要 Customer 和 Template 两个服务的共同参与。其中 Customer 服务是整个业务的起点,它先是调用了 Template 服务注销券模板,然后再调用本地方法注销了由该模板生成的优惠券。说白了,我们就是在两个不同的微服务中,分别使用 Update SQL 语句修改了底层数据。
我们接下来就基于“删除券模板”场景,看一下 Seata AT 背后的业务流程。在开始之前,我需要先花点时间带你认识下 Seata 框架的三个重要角色,TC、TM 和 RM。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Seata AT方案通过Nacos和Seata的结合,实现了无侵入式的编程体验,为分布式事务提供了高效的解决方案。文章首先介绍了Seata AT的底层原理,包括TC、TM和RM三个重要角色,以及业务流程的两个阶段执行。其核心在于undo_log表的记录回滚日志,实现了一阶段和二阶段的独立本地事务执行,以及异步化的全局事务提交和回滚。接着,文章通过实际业务模型展示了Seata AT的底层原理,以及在微服务项目改造中的应用。通过添加依赖项、声明数据源代理和添加Seata配置项,读者能够了解如何在微服务中实现Seata AT的解决方案。整体而言,本文通过清晰的解释和实际案例,帮助读者快速了解了Seata AT方案的技术特点和应用方法。 Seata的配置项定义在application.yml文件中,分为上下两部分,一部分在spring.cloud.alibaba节点下面,它指定了当前应用的事务分组;另一部分在根节点seata下面,定义了连接Seata Server的方式。在项目启动的时候,Seata框架会尝试从Nacos获取Seata Server的地址信息,执行这个操作的类是NacosRegistryServiceImpl。在开启Seata分布式事务的时候,你必须把异常抛出到全局事务的发起方,让@GlobalTransactional注解的方法能够感知到这个异常,才能顺利触发事务的回滚。 文章还展示了一个删除券模板的分布式事务用例,通过@GlobalTransactional注解开启分布式事务,展示了全局事务的回滚操作。最后,文章提出了对Seata AT方案的思考,建议在本地业务非常简单的情况下,不必引入Seata,而是使用传统的事务型消息+日志补偿+跑批补偿的方式。整体而言,本文对Seata AT方案进行了全面的介绍和应用案例展示,为读者提供了深入了解分布式事务解决方案的机会。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Spring Cloud 微服务项目实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(14)

  • 最新
  • 精选
  • 药味
    怎么理解"传统的事务型消息 + 日志补偿 + 跑批补偿的方式"

    作者回复: 使用MQ的事务消息模式 + 事务日志表记录执行状态 + batch job扫表做反向补偿。最经济实惠的方法

    2022-03-02
    5
    12
  • 奔跑的蚂蚁
    大佬,能加个餐 详情说下 传统的方式嘛,最好再说点rocketMq

    作者回复: 传统的方式其实就是利用MQ的事务型消息,或者整一个事务表控制执行状态(有的干脆就直接在业务表上记状态也成),再加一个batch job定时跑批补偿。没啥高端的货

    2022-03-02
    4
    5
  • 奔跑的蚂蚁
    今天用seata 遇到一个问题,没有配置代理数据源 好像也能使用,请问下老师 这个和配置数据源在使用上有什么区别嘛

    作者回复: 同学发现了一个小机关,没错,这个是在0.9版里的一个改进,不用再显示的声明,seata框架会在背后把datasource放到proxy里。我在课程里把这一步单独拿了出来手动操作,主要是想让大家对seata底层的工作原理,即数据源代理,有一个直观一些的认识

    2022-03-15
    4
  • peter
    请教老师几个问题啊: Q1:undo_log问题: A undo_log是文件还是数据库的表?从文中看,似乎是数据库的表。B 如果是表的话,该表由seata框架自己创建并维护,不需要开发人员维护,对吗? Q2:RM是怎么监测到业务代码的DB操作的? 既然seata AT方案是无感知的,那seata框架又是怎么知道业务代码做了哪些DB操作? Q3:阶段二回滚的时候,RM 无法获取本地锁,它会原地打转不停重试。一直处于这个状态吗?这样岂不是相当于死机了? Q4:阶段一,每个本地事务会提交或回滚吗? 每个本地事务不都是在阶段二执行提交或回滚吗? Q5:能否单独讲一讲"“传统的事务型消息 + 日志补偿 + 跑批补偿的方式”? 比如以加餐形式写一章?

    作者回复: 1. 数据库表,seata框架做CRUD 2. 通过GlobalTransactional注解和datasource拦截器 3. 不会,因为当前业务在二阶段了,一定已经持有了全局锁。另一个拿到本地锁的业务会因为无法获取全局锁而回滚,进而释放本地锁 4. 回滚是二阶段异步执行

    2022-03-02
    2
    3
  • Geek_eabafe
    姚老师,阶段二是全局事务的 Commit 和 Rollback 是异步执行。 1. 这里的异步执行是指哪里异步呢? 2. 如果异步执行失败了 TC 仍认为整个事务已经结束了吗? 如果是这样 肯定有脏数据的

    作者回复: 1. 异步简单来说,就是一旦服务被认为应该rollback,那么框架不会使用“阻塞式”的方式来执行rollback,而是异步去通过seata记录的rollback info来做回滚,上层调用方的体验是“fast fail” 2. 是的,框架不能100%保证一致性,总会有很特例的情况,就像早期TCC框架在蚂蚁应用的时候,这些个团队每天来了就要处理各种悬挂问题。因此从seata协调器和框架层面做各种error handling的同时,使用告警机制通知人工介入仍然是一个兜底策略

    2024-01-11归属地:北京
  • Amy
    老师,请教下几个问题 1.RM执行第一阶段完成,是不是可以理解为对于mysql来说已经执行了commit,只是在undo_log表中记录了回滚的数据,第二阶段依赖这个数据对数据进行还原 2.基于问题1,如果RM1执行了一个update操作,比如把id=1的姓名从张三更新了李四,那RM2,第一阶段还没执行完,此时有其他的业务B去查id=1的数据,取出的名字是李四,然后RM2执行失败,触发了RM1的回滚操作,这个时候业务B查的不就是错误数据了吗

    作者回复: 没错,一阶段commit其实已经提交了happy flow里的业务数据,并记录rollback上下文。问题二,分布式方案要在可用性和一致性之间做取舍,如果一定要保证一致性那么就是类似重量级xa方案,那么seata相当于牺牲了一部分一致性换来了可用性的提升。 针对你说的这个问题,在写阶段由于全局锁本地锁的机制在,不会出现对同一条记录的并发修改。但读的业务里,你就要考虑这个业务对一致性的容忍程度是多少,如果要将读来的数据做任何写操作且不一致性低容忍,那么通常做法就是业务层做日志表,代替框架的lock机制,或者最终修改的时候sql update里做版本控制(version字段)

    2023-05-16归属地:北京
  • Q
    老师customer调template卡流程了,脑壳痛 template服务启动一直报 ERROR [coupon-template-serv,,] 21120 --- [ main] i.s.c.r.netty.NettyClientChannelManager : no available service 'null' found, 这个错 customer调template的时候报这个错Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: Unable to commit against JDBC Connection; nested exception is org.hibernate.TransactionException: Unable to commit against JDBC Connection] with root cause,我查了下是jpa和seata在强数据库资源,

    作者回复: 看上去可能是seata锁占用的问题,同学你打开seata的日志,如果是global/local锁竞争应该有相关error log打印出来,盯紧Rollback关键字,看一下报错的具体error是什么

    2022-06-25
  • 西门吹牛
    本地锁该如何理解呢?

    作者回复: 本地锁可以理解为当前微服务对应的后台DB中,该次请求所操作的对象上的锁,生命周期绑定本地事务

    2022-06-02
  • 天天有吃的
    请问下,阶段二是全局事务的 Commit 和 Rollback 是异步执行。这里的异步执行是指哪里异步呢?
    2023-11-09归属地:广东
  • 天天有吃的
    这个图中,tm也是rm吗
    2023-11-09归属地:广东
收起评论
显示
设置
留言
14
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部