Spring Cloud Alibaba 七天训练营(七)分布式事务

本文涉及的产品
应用实时监控服务-用户体验监控,每月100OCU免费额度
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 对文档有任何问题,请在评论区留言!
文档目录

1. 简介

分布式一致性是分布式系统亟需解决的关键问题之一,根据过去一年的调查问卷,在微服务的实践中分布式事务是用户遇到的最大痛点。目前市面缺少经过洪荒流量验证的分布式事务组件,Seata 在阿里经济体内部经过了漫长的孵化,承载了双11洪荒流量,实践证明 Seata 是一款解决分布式数据一致性的的优秀组件。Seata 于 2019 年正式对外开源,开源后就受到了大家的热情追捧,一度蝉联 GitHub 活跃排名榜首。Seata 除了提供了独创的 AT 事务模式外,还扩展了 TCC、Saga 和 XA 事务模式,满足大家对于不同业务场景中的需求。相关详细信息可参考其官网 Seata官网

2. 学习目标

  • 理解分布式事务在业务中的核心使用场景和常用解决方案
  • 理解 Seata AT 事务模式的核心原理
  • 掌握 Seata 作为分布式事务组件与 Spring Cloud 的整合
  • 如何扩展一个 RPC 框架
  • Seata 实战

3. 为什么需要分布式事务?

分布式事务不是在新架构下产生的新问题,即使在单体应用中同样存在着分布式事务问题,典型的场景是单体应用执行方法中含有多个数据源。X/OPEN 对于这一问题,提出了含有三种角色的 DTP(Distributed Transaction Processing)模型并形成了 XA 规范来解决此问题。各厂商针对 XA 规范做了具体的实现,也就是大家常说的 XA协议。在 Java 体系中基于 DTP 模型提出了 JTA规范(参考 JSR 907), 定义了分布式事务中的事务管理器(TM)与资源管理器(RM)、应用程序(AP)等的 Java 接口。在Java EE时代,应用服务器如weblogic 充当了 TM 的角色,而传统关系数据库通过实现 XA 协议充当了 RM 的角色。

随着互联网的高速发展,庞大的用户群体和快速的需求变化已经成为了传统架构的痛点。在这种情况下,如何从系统架构的角度出发,构建出灵活、易扩展的系统来快速响应需求的变化,同时,随着用户量的增加,如何保证系统的稳定性、高可用性、可伸缩性等等,成为了系统架构面临的挑战。微服务基于此背景应运而生,微服务架构越来越来越成为一种架构趋势,其本质是分布式去中心化。但微服务架构绝不是银弹,它不一定是一种能支撑未来一二十年的架构,引入微服务架构时需要我们根据业务场景,系统复杂性和团队规模有步骤的进行。微服务架构的引入使分布式数据一致性问题更为突出,由原来的单体应用拆分出来几十甚至上百个微服务,如何保证服务间的一致性?当在一条较长的微服务调用链中,位于中间位置的微服务节点出现异常,如何保证整个服务的数据一致性?

分布式一致性的引入,一定不可避免带来性能问题,如何更高效的解决分布式一致性问题,一直是我们致力于解决此问题的关键出发点。在“一切都正常”的情况下,我们可以认为我们并不需要分布式事务。但系统很难满足这种理想状态,系统可能因为一个非法的参数校验无法将服务链路继续向下调用下去,系统可能出现令人反感的超时问题,我们不清楚被调用的服务是否真正的执行了,被调用服务可能正在部署,网络抖动亦或者节点宕机导致接口无法继续调用。这些问题普遍存在于我们的系统中,业务的本质体现在数据上,数据不一致的直接后果是可能产生资损,更严重的是如果不一致的数据不能被及时发现,业务再次基于此数据的进行相关逻辑操作,会进一步导致数据错上加错,最终很难溯源。

4. 常见的分布式事务解决方案

从是否满足事务 ACID 特性上,我们可以将事务分为两大类:刚性事务和柔性事务。在常见解决方案中XA事务属于刚性事务解决方案,而其他的大多数解决方案如 TCC、Saga、消息最终一致性则属于柔性事务解决方案。以下将对几种常见的事务方案做简要的介绍:

消息最终一致性

消息最终一致性方案是在Seata问世之前,市面上应用最广泛的一种解决方案。它本身具有削峰填谷,可异步化的优点,更多的适应于可异步化的末端链路消息通知场景。但是它本身也存在着一些缺点:需要依赖可靠消息组件,消息的可靠性很重要,大多数的原生消息组件故障时很难降级;实时性比较差,要经过多次网络IO开销和持久化,遇到队列积压情形实时性不可控;无法保证隔离性,在已发送消息和消息消费之前,中间数据对外可见,无法满足事务 isolate 特性;只能向前重试不可向后回滚,消息消费无法成功时无法回滚消息生产侧的数据;无法保证多条消息间的数据一致性。

XA

XA 标准提出后的20多年间未能得到持续的演进,在学术界有协议优化和日志协同处理等相关的研究,在工业界使用XA落地方案的相对较少,主要集中在应用服务器的场景。XA方案要求相关的厂商提供其具体协议的实现,目前大部分关系数据库支持了XA协议,但是支持程度不尽相同,例如,MySQL 在5.7 才对 xa_prepare 语义做了完整支持。XA 方案被人诟病的是其性能,其实更为严重的是对于连接资源的占用,导致在高并发未有足够的连接资源来响应请求成为系统的瓶颈。在微服务架构下 XA 事务方案随着微服务链路的扩展成为一种反伸缩模式,进一步加剧了资源的占用。另外 XA 事务方案要求事务链路中的resource全部实现XA协议方可使用,若其中某一资源不满足,那么就无法保证整个链路的数据一致性。

TCC

TCC 方案要求用户根据业务场景实现 try,confirm,cancel三个接口,由框架根据事务所处的事务阶段和决议来自动调用用户实现的三个接口。从概念上TCC框架可以认为是一种万能框架,但是其难点是业务对于这三个接口的实现,开发成本相对较高,有较多业务难以做资源预留相关的逻辑处理,以及是否需要在预留资源的同时从业务层面来保证隔离性。因此,这种模式比较适应于金融场景中易于做资源预留的扣减模型。

Saga

有了 TCC 解决方案为什么还需要 Saga 事务解决方案?上文提到了 TCC 方案中对业务的改造成本较大,对于内部系统可以自上而下大刀阔斧的推进系统的改造,但对于第三方的接口的调用往往很难推动第三方进行 TCC 的改造,让对方为了你这一个用户去改造 TCC 方案而其他用户并不需要,需求上明显也是不合理的。要求第三方业务接口提供正反接口比如扣款和退款,在异常场景下必要的数据冲正是合理的。另外,Saga 方案更加适应于工作流式的长事务方案并且可异步化。

上面提到了4种常用的分布式事务解决方案,Seata 集成了TCC、Saga 和 XA 方案。另外,Seata 还提供了独创的 AT 强一致分布式事务解决方案。下文将对 AT 方案进行简要的介绍。

5.  AT事务模式

1.png

一个分布式事务有全局唯一的xid,由若干个分支事务构成,每个分支事务有全局唯一的branchId。上图展示了在一个分支事务中RM 与 TC 的交互过程。其中主要包含的交互动作如下:

branchRegister

分布式事务一阶段执行,分支事务在commit 之前与 TC 交互获取 全局锁 和返回 branchId。全局锁为Seata 应用锁等同于修改数据记录的行锁,若获取锁失败将会进行锁重试,此处提供了两种重试策略是否持有数据库连接重试全局锁,默认为释放数据库连接。若成功,则抢占全局锁并返回branchId,若重试到最大次数失败,则发起全局事务的回滚,对已完成的分支事务执行回滚。

branchReport

分布式事务一阶段执行,本地事务commit 之后与 TC 交互,上报本地事务已完成标识。目前 branchReport 动作已经在 1.0 版本做了相关的优化,本地事务commit 不上报,本地事务rollback 上报。经过优化分布式事务的整体性能在globalCommit 场景下最低提升25%,最高提升50%。本地事务rollback 上报可以帮助 TC 快速决策需要回滚的分支事务。

branchCommit

分布式事务二阶段执行,在形成globalCommit 决议后执行。AT模式中此步骤异步执行来提升其性能,可以认为分布式事务globalCommit决议提交到TC 释放完全局锁就已经完成了整个分布式事务的处理。branchCommit 在AT模式主要用于删除一阶段的undo_log,TC下发到RM后并不是立即执行,而是通过定时任务+sql 批量合并的方式来提升其处理性能。

branchRollback

分布式事务二阶段执行,在形成globalRollback 决议后执行。RM 收到 branchRollback 请求,取undo_log 表中对应的branchId 记录解析rollback_info 字段,对现有数据和undo log后镜像对比,对比不同则分支事务回滚失败。对比成功则根据前镜像构造sql并执行反向操作和删除undo log。

详细处理过程和原理,可参考官网文档关于AT模式的介绍:https://seata.io/zh-cn/docs/dev/mode/at-mode.html

6.  Seata 与 Spring Cloud  集成

2.png

如上图,Seata 与 Spring Cloud Alibaba 集成代码结构如上图所示。从代码上可以分为三大部分:rest、feign 和  web。AutoConfiguration 结尾的类是 [@Configuration ] 类被 spring.factories 加载,负责创建 package 中所属的 bean。

rest

对应restTemplate调用,实现 ClientHttpRequestInterceptor 接口,将当前事务上下文包装到HttpRequest header中,加入到拦截器列表中。

feign

对应openFeign调用,这部分实现了事务上下文传递,与 Hystrix、Sentinel 、Ribbon 组件集成功能。需要特别注意是Hystrix中跨线程的事务上下文传递。这部分代码大量使用了Builder、Wrapper模式,有兴趣的同学可深入阅读。

web

对应Spring Web Servlet中的处理,实现了 HandlerInterceptor接口。在 preHandle 预处理中取 httpRequest header中 Seata的事务上下文并使用 API 绑定到当前线程的事务处理上下文中,这种后续的数据源操作就自动加入到了分布式事务的链路中;在 afterCompletion 中做了当前线程事务上下文的清除,防止事务上下文在线程中污染。

7.  如何扩展一个RPC框架?

在上一章节,我们讲到了Seata 是如何与 Spring Cloud 相集成的。Seata 目前已经集成了 Spring Cloud、Alibaba Dubbo、Apache Dubbo、Motan、gRPC 和  sofa-RPC 等微服务调用。结合上一节与Spring Cloud 的集成,扩展一个RPC 框架我们需要做哪些工作呢 ?主要可以分为两大部分:

事务上下文传递

Seata 的事务上下文目前主要包含:xid和调用服务的分支事务类型。xid 为一个分布式事务的全局唯一标识,类似于Tracing中的 traceId,只有将 xid 传递下去才可能加入到分布式事务的链路中。调用服务的分支事务类型主要用于非 AT模式,例如在一个 TCC 分支事务中不能再嵌套 AT 分支事务。主流的RPC框架大多是基于TCP协议之上的私有协议封装或者是基于HTTP协议。Seata 的事务上下文标识都是简单的字符串,序列化由RPC框架直接完成,大多数RPC 框架实现了 filter 或者 interceptor 接口,通过将Seata的事务上下文填充到协议中的attachment字段或者http header中,就可以简单的完成事务上下文的传递。

事务上下文绑定和清除

在 RPC 的 provider 端收到 consumer 的请求,将事务上下文取出,通过 API 绑定到当前的执行线程中,这样后续的业务处理都纳入到了Seata 的分布式事务链路中。执行完业务处理后,需要对绑定到当前线程的事务上下文清除掉,防止产生线程事务上下文污染。

具体 API 可参考官网文档:https://seata.io/zh-cn/docs/user/api.html

请大家思考一下如何去与Dubbo 集成的呢?https://github.com/seata/seata/tree/develop/integration/dubbo

8.  Seata 实战

本章节将通过一个基于Spring Cloud的订单和库存服务进行Seata 实战。

我们在沙箱环境里准备好了一套seata的实际应用案例,服务调用结构如下所示:

3.png

如图所示,服务链路中包含三个微服务:business(微服务入口)、order(订单服务)和 storage(库存服务)。

业务逻辑

通过url 调用 business 服务,business 服务会通过 openFeign 的方式分别调用 storage 和  order 服务。每个服务调用后会根据正常(ok)或异常(fail)的返回值决定是否抛出异常,若返回结果不为 ok 那么 business 将抛出异常,触发整个事务回滚,预期数据至 business 方法执行前的数据并且库存总量和与初始值一致。当order 和 storage 两个服务调用正常,用户可以根据 url 中的 mockException=true 或 false 来注入一个 mock 异常,当注入异常后,期望数据回滚至  business 方法执行前的数据并且库存总量和与初始值一致。

异常模拟

  1. 在 bussiness 中请求超过现有库存,通过参数 count 来指定要扣减的库存数量,当超出库存,将抛出异常进行事务回滚。
  2. 在 bussiness 中请求中加入 mockException=true 参数,触发事务回滚。

启动步骤

以下请求 url 中的 localhost 请根据实际值进行替换。

启动order 和  storage 服务,最后启动  business 服务。服务的注册和发现,Seata服务注册和发现 在这里使用了 Nacos 启动成功后,可以通过Nacos 控制台的sandbox-seata namespace 看到如下服务:

4.png

访问 business 的url : http://localhost:8080/seata/check 来检查初始化数据

5.png

通过访问 business 的url:http://localhost:8080/seata/feign?count=5&mockException=true 来触发业务逻辑:

6.png

其中count 代表扣减库存的数量,当库存不足将触发事务回滚;mockException代表是否触发业务异常,设置为true 会触发业务异常,并通过分布式事务实现回滚。

每次操作完business 请求后,访问 business 的url : http://localhost:8080/seata/check 来检查操作后数据。

重复以上3(根据实际需要请求,不必每次请求相同),4步骤,最后再次通过访问 business 的url : http://localhost:8080/seata/check 来检查结果数据:

7.png

使用总结

  1. 引入依赖。com.alibaba.cloud:spring-cloud-starter-alibaba-seata 中包含了 io.seata:seata-spring-boot-starter 依赖。若于期望依赖 seata 的版本不一致,可手动排除重引入。com.alibaba.cloud 原生 版本说明
parent:
<dependencyManagement>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${alibaba.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
    </dependencyManagement>
    
    module:
     <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>
    </dependencies>
  1. 添加配置文件,具体配置项说明参考此处
seata:
   enabled: true
   application-id: business
   tx-service-group: my_test_tx_group
   config:
      type: nacos
      nacos:
         namespace: "sandbox-seata"
         serverAddr: 139.196.203.133:8848
         group: SEATA_GROUP
         username: xxx
         password: xxx
   registry:
      type: nacos
      nacos:
         application: seata-server
         serverAddr: 139.196.203.133:8848
         group: SEATA_GROUP
         namespace: "sandbox-seata"
         username: xxx
         password: xxx

在所有业务库中创建 undo_log 表,不同的数据库类型脚本参考此处 ,示例中已自动完成创建。

在需要纳入分布式事务链路的入口service 方法(保证可使 Spring 切面生效的位置亦可)上添加 [@GlobalTransactional ] 注解。

9.  其他

Seata 更多sample样例 ,请参考  样例

Seata 社区联系方式,请参见 联系我们

欢迎大家试用阿里云商业化产品  GTS,更高性能,更稳定,全面兼容 Seata。

相关文章
|
3月前
|
SpringCloudAlibaba API 开发者
新版-SpringCloud+SpringCloud Alibaba
新版-SpringCloud+SpringCloud Alibaba
|
26天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
13天前
|
存储 人工智能 Java
Spring AI Alibaba 配置管理,用 Nacos 就够了
本文通过一些实操案例展示了 Spring AI Alibaba + Nacos 在解决 AI 应用中一系列复杂配置管理挑战的方案,从动态 Prompt 模板的灵活调整、模型参数的即时优化,到敏感信息的安全加密存储。Spring AI Alibaba 简化了对接阿里云通义大模型的流程,内置 Nacos 集成也为开发者提供了无缝衔接云端配置托管的捷径,整体上极大提升了 AI 应用开发的灵活性和响应速度。
117 12
|
2月前
|
JSON SpringCloudAlibaba Java
Springcloud Alibaba + jdk17+nacos 项目实践
本文基于 `Springcloud Alibaba + JDK17 + Nacos2.x` 介绍了一个微服务项目的搭建过程,包括项目依赖、配置文件、开发实践中的新特性(如文本块、NPE增强、模式匹配)以及常见的问题和解决方案。通过本文,读者可以了解如何高效地搭建和开发微服务项目,并解决一些常见的开发难题。项目代码已上传至 Gitee,欢迎交流学习。
149 1
Springcloud Alibaba + jdk17+nacos 项目实践
|
2月前
|
人工智能 Java API
阿里云开源 AI 应用开发框架:Spring AI Alibaba
近期,阿里云重磅发布了首款面向 Java 开发者的开源 AI 应用开发框架:Spring AI Alibaba(项目 Github 仓库地址:alibaba/spring-ai-alibaba),Spring AI Alibaba 项目基于 Spring AI 构建,是阿里云通义系列模型及服务在 Java AI 应用开发领域的最佳实践,提供高层次的 AI API 抽象与云原生基础设施集成方案,帮助开发者快速构建 AI 应用。本文将详细介绍 Spring AI Alibaba 的核心特性,并通过「智能机票助手」的示例直观的展示 Spring AI Alibaba 开发 AI 应用的便利性。示例源
|
2月前
|
人工智能 开发框架 Java
总计 30 万奖金,Spring AI Alibaba 应用框架挑战赛开赛
Spring AI Alibaba 应用框架挑战赛邀请广大开发者参与开源项目的共建,助力项目快速发展,掌握 AI 应用开发模式。大赛分为《支持 Spring AI Alibaba 应用可视化调试与追踪本地工具》和《基于 Flow 的 AI 编排机制设计与实现》两个赛道,总计 30 万奖金。
|
2月前
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
2月前
|
人工智能 Java API
阿里云开源 AI 应用开发框架:Spring AI Alibaba
阿里云开源 Spring AI Alibaba,旨在帮助 Java 开发者快速构建 AI 应用,共同构建物理新世界。
|
2月前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
3月前
|
消息中间件 Java 对象存储
数据一致性挑战:Spring Cloud与Netflix OSS下的分布式事务管理
数据一致性挑战:Spring Cloud与Netflix OSS下的分布式事务管理
54 2