首页 > 其他分享 >Seata Saga 模式快速入门和最佳实践

Seata Saga 模式快速入门和最佳实践

时间:2023-06-19 14:02:57浏览次数:48  
标签:事务 Seata Saga 流程 模式 状态机 入门

作者:王特(亦夏)

Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。Seata 为用户提供了 AT、TCC、SAGA、XA 等多种事务模式,帮助解决不同业务场景下的事务一致性问题。

本文主要介绍 Seata Saga 模式的使用以及最佳实践,围绕三个部分展开,第一部分是 Seata Saga 的简介、第二部分是带大家快速入门,学习怎么使用 Seata Saga 模式,最后一部分将会给大家分享一些 Seata Saga 实践中的经验,帮助用户更快、更好得使用 Seata Saga 模式。

Seata Saga 简介

1.1 Saga 模式

Saga 模式是分布式事务的解决方案之一,理念起源于 1987 年 Hector & Kenneth  发表的 Sagas 论文。它将整个分布式事务流程拆分成多个阶段,每个阶段对应我们的子事务,子事务是本地事务执行的,执行完成就会真实提交。

Seata Saga 模式快速入门和最佳实践_JSON

它是一种基于失败的设计,如上图,可以看到,每个活动或者子事务流程,一般都会有对应的补偿服务。如果分布式事务发生异常的话,在 SAGA 模式中,就要进行所谓的‘恢复’ ,恢复有两种方式,逆向补偿和正向重试。比如上面的分布式事务执行到 T3 失败,逆向补偿将会依次执行对应的 C3,C2,C1 操作,取消事务活动的 ‘影响’。那正向补偿,它是一往无前,T3 失败了,会进行不断重试,然后继续按照流程执行 T4,T5 等。

根据 Saga 模式的设计,我们可以得到 Saga 事务模式的优缺点。

优点:

  • 子事务(或流程),提交是本地事务级别的,没有所谓的全局锁,在长事务流程下,避免了长时间的资源锁定;另外这种流水线的处理模型天然符合阶段式信号处理模型,能发掘出更高的性能和吞吐。
  • 正向服务和补偿服务都是交给业务开发实现的,所以 Saga 模式和底层数据库协议是无关的。XA/AT 模式可能依赖特定的数据库类型和版本,比如 MySQL 是 5.0 之后才支持的 XA,那么低版本的 MySQL 就不能适用到XA模式。

缺点:

  • 也是因为正向服务和补偿服务都由业务开发者实现,所以业务上是有开发成本的,侵入性相对 XA/AT 打一个注解的方式会高很多。
  • 因为一阶段子事务活动提交是本地事务级别的,所以 Saga 模式不保证隔离性。提交之后就可能‘影响’其他分布式事务、或者被其他分布式事务所‘影响’。例如:其他分布式事务读取到了当前未完成分布式事务中子事务的更新,导致脏读;其他分布式事务更新了当前未完成分布式事务子事务更新过的字段,导致当前事物更新丢失;还有不可重复读的场景等。

所以 Saga 模式的使用也需要考虑这些问题带来的‘影响’。一般 Saga 模式的使用场景有如下几个:

  • 长事务流程,业务上难以接受长时间的资源锁定,Saga 的特性使得它在长事务流程上处理非常容易;
  • 业务性质上,业务可以接受或者解决缺乏隔离性导致的‘影响’。例如部分业务只要求最终一致性,对于隔离性要求没有那么严格,其实是可以落地 Saga 模式的;
  • 分布式事务参与者包含其他机构或者三方的服务,数据资源服务不是我们自身维护,无法提供 TCC 模式要求的几个接口。

1.2 Seata Saga

接下来我们看看 Seata Saga 的实现,Saga 主流的实现分为两种:编排式和协调式。 Seata Saga 的实现方式是编排式,是基于状态机引擎实现的。状态机执行的最小单位是节点:节点可以表示一个服务调用,对应 Saga 事务就是子事务活动/流程,也可以配置其补偿节点,通过链路的串联,编排出一个状态机调用流程。在 Seata 里,调用流程目前使用 JSON 描述,由状态机引擎驱动执行,当异常的时候,我们也可以选择补偿策略,由 Seata 协调者端触发事务补偿。

有没有感觉像是服务编排,区别于服务编排,Seata Saga 状态机是 Saga+ 服务编排,支持补偿服务,保证最终一致性。

我们来看看一个简单的状态机流程定义:

Seata Saga 模式快速入门和最佳实践_分布式事务_02

上方是一个 Name 为 reduceIncentoryAndBalance 的状态机描述,里面定了 ServiceTask 类型的服务调用节点以及对应的补偿节点 CompensateReduceInventory。

看看几个基本的属性:

  • Type:节点类型,Seata Saga 支持多种类型的节点。例如:ServiceTask 是服务调用节点。
  • ServiceName/ServiceMethod:标识 ServiceTask 服务及对应方法
  • Input/Output:定义输入输出参数,输入输出参数取值目前使用的是 SPEL 表达式。
  • Retry:控制重试流程
  • Catch/Next:用于流程控制、衔接,串联整个状态机流程

更多类型和语法可以参考 Seata 官方文档 [ 1] ,可以看到状态机 JSON 声明还是有些难度的,为了简化状态机 JSON 的编写,我们也提供了可视化的编排界面 [ 2] ,如下所示,编排了一个较为复杂的流程。

Seata Saga 模式快速入门和最佳实践_状态机_03

话不多说,我们进入下面的实践环节。

Seata Saga 使用入门

2.1 从 Seata 官网新人文档开始

Seata 分 TC、TM 和 RM 三个角色,TC(Server 端)为单独服务端部署,TM 和 RM(Client 端)由业务系统集成。

Server 端存储模式(store.mode)现有 file、db、redis 三种(后续将引入 raft,mongodb),file 模式无需改动,直接启动即可。

2.1.1 部署 Seata Server

从新人文档,可以看出 Seata 还是传统的 CS 模型。首先我们需要部署下 Seata Server 端。Server 端默认的存储模式是 file 模式,无需改动,直接执行 springboot 启动类 main 方法即可启动 Seata Server。为了方便,本次演示就使用 file 模式启动,其他模式的启动方式可以参考新人文档的详细介绍。

2.1.2 创建 Client 端测试应用

同时我们需要创建一个客户端的测试应用,这里命名 seata-saga-test,测试应用使用 springboot 框架,配置好 spring 的 aplication.pname 和 port,并且引入 seata-spring-boot-starter 依赖,完成 Client 端应用的搭建。

Seata Saga 模式快速入门和最佳实践_分布式事务_04

2.2 从Seata Saga单元测试看起

一般了解一个框架的功能,建议是从入口的单元测试类开始看起。在 Seata 仓库中找到 Seata Saga 的 test 模块,从最外围的测试类 io.seata.saga.engine.StateMachineTests 看起(一般开源项目最外围的测试类即是入口类):

Seata Saga 模式快速入门和最佳实践_JSON_05

从上面的截图可以看出,入口测试方法主要分为三个部分。

【1】处的 spring 配置文件声明了 StateMachineEngine Bean 以及对应的属性,【2】处也引用了该类执行 start,判断该类为我们状态机的入口类,其实 StateMachineEngine 该类也就是 Seata Saga 状态机操作入口,控制状态机的开始、恢复等操作。StateMachineEngine 有一个重要的属性 resources,该属性声明了状态机 JSON 文件的存储路径,Seata Saga 状态机引擎启动的时候会加载对应路径下的状态机定义,以供后续使用,这里的路径根据我们需求更改。

【3】处调用了 StateMachineEngine 的 start 方法,传递状态机名称,启动参数,开启一个状态机流程调用,简单跟下实现,可以看到其中状态名称对应 resources 路径下状态机 JSON 定义中的 Name 属性。

测试 Seata Saga 状态机流程,我们得先有一个状态机 JSON 定义。使用 Seata Saga StateMachine Designer,定义一个简单 AService#doA 方法调用 BService#doB 方法的状态机流程,再加个入参,最终我们的类#方法和状态机 JSON 如下所示。

Seata Saga 模式快速入门和最佳实践_分布式事务_06

有了基础的调用模型和状态机 JSON 定义,按照测试用例,我们同样声明出状态机 Bean 及执行入口 (注意:start 方法里面的状态机名称需要和状态机 JSON 定义里面的 Name 名称保持一致) ,执行下 main 方法,我们可以发现 AService#doA 方法和 BService#doB 方法都被成功调用了。

Seata Saga 模式快速入门和最佳实践_分布式事务_07

至此,我们已经完成了 Seata Saga 状态机的入门使用。继续观察单测,我们发现 Seata Saga 单测还有两个模块,分表是 db 和 mock。

Seata Saga 模式快速入门和最佳实践_分布式事务_08

我们先来看看 db 模块的单测,可以看到 db 模块的单测类和上面基本类似,唯一的区别就在于 StateMachineEngine,指定了 db 存储,执行了 ddl sql(初始化 Seata Saga 相关表)。指定了 db 存储,那么我们的状态机执行过程将会持久化在 db 存储,方便事务执行过程查询和异常恢复,也是生产环境的实践方式。

Seata Saga 模式快速入门和最佳实践_分布式事务_09

mock 模块通过 mock transcation,脱离 Seata Sever,仅使用了 Seata Saga 的服务编排能力。有兴趣的同学可以再去实践下 db 和 mock 模块的使用,这里就不展开了。

Seata Saga 最佳实践

3.1 基本使用

  • 在应用层面,Seata Saga 状态机模式使用上不同于 AT、TCC 注解化方式,要使用状态机 API 执行;
  • 在状态机模式里面,恢复策略分为向前重试和向后补偿,根据业务场景,要选择合适的补偿策略;
  • Seata Saga 支持异步状态执行、状态机异步执行,适时使用异步,可以提升整个系统的吞吐量。

3.2 Saga 服务

  • Saga 服务可能被多次调用,所以 SAGA 服务要保证幂等;
  • 补偿服务较原服务可能先执行、需要允许空补偿、同时需要拒绝后续的原服务请求,进行防悬挂控制;

3.3 隔离性问题应对

  • 业务驱动,如果业务上可以接受缺乏隔离性的影响,可以不用做任何操作;
  • 语义锁。对操作资源进行语义级别的锁定;
  • 使用悲观流程,例如 A->B 转账操作,先给 B 加钱,再给 B 减钱 换成悲观视图就是先给 A 减钱,再给 B 加钱,防止 B 加钱之后立刻消费导致的短款问题;
  • 其他方式。

3.4 稳定性

基于 DB 存储的 Saga 模式,需要注意:重试或者补偿默认会插入一条状态执行记录,频繁重试或者补偿,会导致状态执行记录爆炸,如果有大对象存储,可能会导致内存 crash。Seata Saga 提供了 update 模式,使用 update 记录代替新增执行记录,用来避免此类问题。

3.5 扩展

  • Seata Saga 状态机存储、语法解析等都是面向 SPI 设计的,业务上可以平滑替换对应的存储或者状态机语言实现。例如将状态机的 JSON 解析替换到YAML解析。
  • Seata Saga 支持 Mock Transaction 的方式,仅使用服务编排能力,也支持状态机定义(JSON)动态发布,也就是编排的动态发布,这一点在做 DSL 动态管控端的时候将会非常有用。

讲了这么多,Seata Saga 目前状态机的实现,上手成本相对还是比较高。一方面我们致力提升 Seata Saga 状态机模式的易用性,同时也在设计 Saga 的注解化模式、流式编排模式,期望提供给用户更具产品化能力的 Seata Saga。有兴趣的同学,也非常欢迎加入共建,搜索钉钉群号,加入Seata Group 开源交流群。(群号:44816898)

相关链接:
[1] Seata 官方文档

<http://seata.io/zh-cn/docs/user/saga.html>

[2] 可视化的编排界面

<http://seata.io/saga_designer/index.html#/>

标签:事务,Seata,Saga,流程,模式,状态机,入门
From: https://blog.51cto.com/u_13778063/6512826

相关文章

  • 网络设备操作入门
    1.路由器、交换机及其操作系统介绍1.1.路由器与交换的作用与特点1.2.路由器的作用1.3.路由器的特点1.4.交换机的作用1.5.交换机的特点1.6.路由器和交换机介绍1.7.路由器1.8.交换机1.9.H3C网络操作设备Commware2.命令行操作基础2.1.连接命令行接口的......
  • 新手入门Web安全的学习路线
    学习Web安全需要掌握Web安全相关概念、渗透测试相关工具、渗透实战操作、熟悉Windows/KaliLinux、中间件和服务器的安全配置、脚本编程学习、源码审计与漏洞分析、安全体系设计与开发等等。如果是零基础的小白入门Web安全,可以参考这个学习规划:第一步:Web安全相关概念建议学习时......
  • Jetpack从入门到几乎入门(一)
    前言Jetpack系列:Jetpack从入门到几乎入门(一)Jetpack从入门到几乎入门(二)Jetpack从入门到几乎入门(三) 本文是我在学习guolin大神的《第一行代码》第三版Jetpack部分的知识总结,文中代码参考自《第一行代码》第三版在阅读本文前,您需要掌握kotlin语言的基本语法且对Activity的生命周期有......
  • 2022最全面&详细的Android学习指南,零基础快速入门的通道
    随着Android技术栈的不断扩展,不少新的技术如Flutter、RN、小程序等涌入我们的视野,也有越来越多的人投身入Android开发的赛道。无论你是35岁正在遭遇中年职业危机的程序员,还是刚刚毕业的大学生/研究生,想走技术这条路,都需要不断学习,风雨兼程!那么,如何系统的学习Android呢?首先来看看And......
  • 快速入门|Flutter完整开发实战详解 谷歌架构师独家分享
    前言这几年在大前端的开发领域,选择跨端方案的公司和部门越来越多,一方面是跨平台的前端框架越来越成熟,另一方面也是因原生开发者正逐年减少。所以,在当下掌握一门跨平台的技术栈还是很有必要的,无论从广度还是从深度都会有所帮助。就目前来说有很多主流的跨平台框架,就比如:Flutter、Rea......
  • WPF 入门笔记 - 05 - 依赖属性
    如果预计中的不幸没有发生的话,我们就会收获意外的喜悦。--人生的智慧-叔本华WPF属性系统这一部分是中途加的,直接依赖属性有点迷糊......
  • 从入门到精通,Android Jetpack 架构实战教程合集
    Jetpack是Google推出的一些库的集合,包含组件、工具、架构方案等,其优势众多:可以减少空指针异常崩溃、内存泄漏,为开发出健壮且流畅的程序提供强力保障;可以消除大量重复样板式的代码,加速Android的开发进程;可以统一开发模式,抛弃传统的MVC,MVP…对于谷歌而言,AndroidJetpack是他......
  • 在 Debian 12 上安装 KubeSphere 实战入门
    老Z,运维架构师,云原生爱好者,目前专注于云原生运维,云原生领域技术栈涉及Kubernetes、KubeSphere、DevOps、OpenStack、Ansible等。前言知识点定级:入门级KubeKey安装部署KubeSphere和KubernetesDebian操作系统的基本配置Kubernetes常用工作负载的创建KubeSphere......
  • 驱动开发:文件微过滤驱动入门
    MiniFilter微过滤驱动是相对于SFilter传统过滤驱动而言的,传统文件过滤驱动相对来说较为复杂,且接口不清晰并不符合快速开发的需求,为了解决复杂的开发问题,微过滤驱动就此诞生,微过滤驱动在编写时更简单,多数IRP操作都由过滤管理器(FilterManager或Fltmgr)所接管,因为有了兼容层,所以在......
  • 借助ChatGPT,7天入门量化投资
    ChatGPT是很好的学习助手。如果是零基础,想快速入门量化投资,该怎么做呢?首先,可以让ChatGPT帮忙制定一个系统的7日学习计划:然后让ChatGPT推荐一些学习资源:有哪些量化交易的入门学习资源推荐,比如视频、论坛、网站等?然后,不懂的地方,可以让ChatGPT做出通俗易懂的讲解;需要编程的时候,可以让......