分布式事务框架Seata

news2025/1/18 9:45:38

分布式事务基础

<<分布式事务基础理论>>

<<分布式事务解决方案>>

Seata 一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

Seata 全局框架

Seata 的设计思路是将一个分布式事务理解成一个全局事务下面挂了多个分支事务,而一个分支事务是一个满足 ACID 的本地事务,因此我们可以操作分布式事务像操作本地事务一样。

在 Seata 内部定义了三个模块来处理全局事务和分支事务:

  • Transaction Coordinator(TC) - 事务协调者: 维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。

  • Transaction Manager (TM)- 事务管理器: 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。

  • Resource Manager (RM) - 资源管理器: 控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。

Seata 提供的 AT、TCC、SAGA 和 XA 事务模式,都是基于这三个模块进行的。Seata 整体的执行步骤为:

  1. TM 向 TC 申请开启一个全局事务,TC 创建全局事务并返回一个唯一的 XID,XID 会在全局事务的上下文中传播。

  2. RM 向 TC 注册分支事务,该分支事务归属于拥有相同 XID 的全局事务。

  3. TM 向 TC 发起全局的提交或回滚。

  4. TC 调度 XID 下的所有分支事务提交或回滚。

AT 模式

在《分布式事务解决方案》中介绍了常见的几种方案,总的来说主要分为两类:对业务无入侵和有入侵的方案。无入侵方案主要有基于数据库 XA 协议,虽然 XA 协议与业务代码解耦,但是它必须要求数据库对 XA 协议的支持,且 XA 协议会造成事务资源长时间得不到释放,锁定周期长,性能很差。有入侵的方案都需要通过在应用层做手脚,比如很出名的 TCC 方案,基于 TCC 也有很多成熟的框架,如 ByteTCC、tcc-transaction 等。

针对以上事务解决方案的痛点,Seata 提出了 AT 模式,也是Seata默认的事务模式

AT 模式的实现原理是在数据源做了一层代理(DataSourceProxy),在代理层中 Seata 加入了一些额外的逻辑,包括解析 SQL,把业务数据在更新前后的数据镜像组织成回滚日志,并将 undo log 日志插入 undo_log 表中,保证每条更新数据的业务 sql 都有对应的回滚日志存在。

AT 模式的执行过程

  • 一阶段:

Seata 拦截“业务 SQL”,首先解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成before image,然后执行“业务 SQL”更新业务数据,在业务数据更新之后,再将其保存成after image,最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。最后生成的before imageafter image会保存到 undo log 表中

  • 二阶段:

如果是提交,因为“业务 SQL”在一阶段已经提交至数据库, 所以 Seata 框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。

如果是回滚,Seata 就需要回滚一阶段已经执行的“业务 SQL”,还原业务数据。回滚方式便是用before image还原业务数据;但在还原前要首先要校验脏写,对比“数据库当前业务数据”和 “after image”,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理。

AT 模式的一阶段、二阶段提交和回滚均由 Seata 框架自动生成,用户只需编写业务 SQL,便能轻松使用分布式事务,AT 模式是一种对业务无任何侵入的分布式事务解决方案。

环境搭建

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

服务端部署

  1. 下载启动包:https://github.com/seata/seata/releases

  2. 建表,主要的表有三个:

  • 全局事务:global_table

  • 分支事务:branch_table

  • 全局锁:lock_table

    在 MySQL 中,创建一个名为 seata 的数据库实例。创建相关表的脚本在 seata-->script-->server-->db目录下

  1. 设置配置中心和注册中心

  • 搭建 nacos,具体的搭建过程自行查资料

  • 配置中心: seata-->conf-->application.yml 修改 seata.config.type="nacos",在 seata-->conf-->application.example.yml 中 seata.config.nacos 下有相关的 nacos 配置,将其复制到 application.yml 下,并将 nacos 相关的数据配置完整。

    设置配置中心可以参考官网:https://seata.io/zh-cn/docs/user/configuration/nacos.html

  • 注册中心: seata-->conf-->application.yml 修改 seata.registry.type="nacos",在 seata-->conf-->application.example.yml 中 seata.registry.nacos 下有相关的 nacos 配置,将其复制到 application.yml 下,并将 nacos 相关的数据配置完整。

  1. 修改存储模式 store.mode
    Server 端存储模式(store.mode)现有 file、db、redis 三种,file 模式无需改动,直接启动即可,下面专门讲下 db,因为 db 模式为高可用模式,全局事务会话信息通过 db 共享。 seata-->conf-->application.yml,修改 store.mode="db"

  2. 修改数据库连接
    seata-->conf-->application.example.yml 中附带额外配置,将其 db 相关配置复制至 application.yml,修改 store.db 相关属性。

  3. 启动

seata-server.sh -h 127.0.0.1 -p 8091 -m db

业务系统集成

  1. 添加依赖,Seata 提供了不同的依赖包。可以根据项目自行选择,建议单选。

  • 依赖 seata-all

  • 依赖 seata-spring-boot-starter,支持 yml、properties 配置(.conf 可删除),内部已依赖 seata-all

  • 依赖 spring-cloud-alibaba-seata,内部集成了 seata,并实现了 xid 传递

  1. 在涉及到的服务的数据库中创建undo_log

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
  1. 初始化 GlobalTransactionScanner,如果引入seata-spring-boot-starterspring-cloud-starter-alibaba-seata等 jar 会自动初始化,否则需要手动初始化。

@Bean
public GlobalTransactionScanner globalTransactionScanner() {
    String applicationName = this.applicationContext.getEnvironment().getProperty("spring.application.name");
    String txServiceGroup = this.seataProperties.getTxServiceGroup();
    if (StringUtils.isEmpty(txServiceGroup)) {
        txServiceGroup = applicationName + "-fescar-service-group";
        this.seataProperties.setTxServiceGroup(txServiceGroup);
    }

    return new GlobalTransactionScanner(applicationName, txServiceGroup);
}
  1. 实现 xid 跨服务传递,如果是 Spring Cloud 项目,并引用了spring-cloud-starter-alibaba-seatajar,则已经自动实现了,否则需要参考源码 integration 文件夹下的各种 rpc 实现 module

业务使用

1、以一个 Spring Cloud 项目为例,项目中有两个服务:订单服务和 库存服务。业务场景为创建订单的同时减库存。

在两个服务中添加依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
</dependency>

2、在每个业务服务下的数据库里添加undo_log表。

3、在每个业务服务下的配置文件中添加 seata 配置

seata:
  tx-service-group: default_tx_group
  registry:
    type: nacos
    nacos:
      application: seata-server # seata server 的服务名seata-server ,如果没有修改可以不配
      server-addr:  127.0.0.1:8848 # seata server 所在的nacos服务地址
      group : DEFAULT_GROUP  # seata server 所在的组,默认就是SEATA_GROUP,没有改也可以不配
      namespace: 0d876b7d-4cfd-4860-bf81-8e5266c9375c # 自己seata注册中心namespace
      username: nacos
      password: nacos
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848 # seata server 所在的nacos服务地址
      username: nacos
      password: nacos
      group: DEFAULT_GROUP
      namespace: 0d876b7d-4cfd-4860-bf81-8e5266c9375c # 自己seata注册中心namespace
  application-id: seata-demo #
  enabled: true

注意

  1. 这里的 group 要与 server 端配置的保持一致

  2. tx-service-group 为事务群组,要部署同一套分布式事务的微服务要求事务群组要一致。可以在 nacos 的配置中查询 :service.vgroupMapping.xxx。

  1. 库存服务 StockController

@PostMapping(value = "/reduct")
public void reduct(String productId) {
    //去库存
    stockService.reduct(order.getProductId());
    // 异常
    int a=1/0;
    return order;
}

在减库存的方法中模拟了一个业务异常int a=1/0,表示服务调用发生异常。

  1. 订单服务中创建调用库存服务的 Feign

@FeignClient(value = "stock-service")
public interface StockApi {
    @PostMapping(value = "/reduct")
   void reduct(String productId);
}

订单服务OrderService,在需要开启全局事务的方法上添加@GlobalTransactional注解

Autowired
private StockApi stockApi;

@GlobalTransactional
public Order create(Order order) {
    // 插入
    orderMapper.insert(order);
    // 减库存
    stockApi.reduct(order.getProductId());
    return order;
}

当调用订单服务时,库存服务发生异常,可以判断发生异常后两个数据库中的数据是否回滚。

参考: https://seata.io/zh-cn/blog/seata-at-tcc-saga.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/364857.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Socket编程 | TCP服务器 之 并发阻塞模型(多进程实现)

TCP服务器IO模型 之 并发阻塞 1. 引言 在 Linux 环境下多进程的应用很多,其中最主要的就是网络/客户服务器。多进程服务器是当客户有请求时,服务器用一个子进程来处理客户请求。父进程继续等待其它客户的请求。这种方法的优点是当客户有请求时,服务器能及时处理客户,特别是…

JavaEE简单示例——动态SQL元素<where>

简单介绍&#xff1a; 在我们之前使用where关键字进行查询的时候&#xff0c;总是会在后面添加一个11恒等式&#xff0c;并且在每一个可能拼接的SQL语句前面都加上一个and关键字&#xff0c;防止当后续的所有条件都不满足的时候&#xff0c;where关键字在最后直接跟and的时候也…

系列三、约束

一、概述 1.1、定义 约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。1.2、作用 保证数据库中数据的正确、有效性和完整性。1.3、分类 注意事项&#xff1a;约束是作用于表中字段上的&#xff0c;可以在创建表/修改表的时候添加约束。 二、演示 需求&am…

DEV C++的使用入门程序做算术运算

DEV C Dev-C &#xff08;有时候也称为 Dev-Cpp&#xff09;是一个免费软件&#xff0c;最早是由 BloodShed 公司开发的&#xff0c;在版本 4.9.2 之后该公司停止开发并开放源代码。然后由 Orwell 接手进行维护&#xff0c;陆续开发了几个版本&#xff0c;后来也有其他开发人员…

基于RK3399+Linux QT地面测试台多参数记录仪测试平台软件设计(二)

rk3399 是由本土芯片厂商瑞芯微&#xff08;Rockchip&#xff09;研发的高性能、低功耗“中国芯”。在 2016 年 4 月&#xff0c;rk3399 首次在香港举行的电子展上亮相。芯片使用六核大 LITTLE 处理器&#xff1a; 包括四核的 Cortex-A53 和双核的 Cortex-A72&#xff0c;主频可…

ubuntu22下phpstorm + xdebug调试php

文章目录前言环境主要步骤xedbug的安装xedbug.so的安装浏览器安装xdebug-helperphpstorm 配置xdebug前言 主要借鉴 https://blog.csdn.net/yinhangbbbbb/article/details/79247331 但是在linux下搭建还是遇到了不少问题 环境 phpstudy phpstorm xdebug 主要步骤 phpstudy、…

Nginx学习 (1) —— 初识Nginx(编译安装、启动停止、简单配置)

文章目录Nginx的发行版本Nginx的编译安装&#xff08;ubuntu18.04&#xff09;Nginx相关操作Nginx启动停止命令安装Nginx为系统服务Nginx的目录结构与基本原理目录结构&#xff1a;基本运行原理&#xff1a;基础配置&#xff1a;核心配置Nginx的发行版本 Nginx开源版&#xff…

【UE4 制作自己的载具】1-使用3dsmax制作载具

学习谌嘉诚课程所做笔记源视频链接&#xff1a;【虚幻4】UE4雪佛兰科迈罗汽车详细制作中文教程&#xff01;&#xff08;汽车骨骼绑定驾驶、动画蓝图&#xff09;汽车模型下载链接&#xff1a;https://pan.baidu.com/s/1ZH5gaAwckzRIZ0w6n0qvIA密码&#xff1a;19sj步骤&#x…

【2023蓝桥杯】2017年第八届C/C++A组真题(解析笔记)

目录 T1&#xff1a;迷宫 - 暴力dfs标注 T2&#xff1a;跳蚱蜢 - 9数算式 全排列 枚举乘号位置 T3&#xff1a;魔方状态 - 模拟 判重 &#xff08;高手入*****&#xff09; T4&#xff1a;方格分割 - dfs 从中心点去切割 T5&#xff1a;字母组串 - 递归思维-搞清楚参数…

Spring架构篇--2.5.4 远程通信基础--Select 源码篇--selector.close()总结

前言&#xff1a;通过selector 的poll 来完成所有socket 事件的监听&#xff0c;当不需要selector时 通过selector.close() 完成通道的关闭和资源的释放&#xff1b; 1 selector.close()关闭&#xff1a; AbstractSelector 类中close 方法&#xff1a; public final void cl…

简单说说OSI网络七层模型

如果你读过计算机专业&#xff0c;或者学习过网络通信&#xff0c;那你一定听说过 OSI 模型&#xff0c;它曾无数次让你头大。OSI 是 Open System Interconnection 的缩写&#xff0c;译为“开放式系统互联”。OSI 模型把网络通信的工作分为 7 层&#xff0c;从下到上分别是物理…

你知道这几种常见的JVM调优场景吗?

看此文前需已了解了运行时的数据区域和常用的垃圾回收算法&#xff0c;也了解了Hotspot支持的垃圾回收器。 一、cpu占用过高 cpu占用过高要分情况讨论&#xff0c;是不是业务上在搞活动&#xff0c;突然有大批的流量进来&#xff0c;而且活动结束后cpu占用率就下降了&#xf…

WebGL和OpenGL的区别及关系

什么是WebGLWebGL™是一个跨平台的&#xff0c;免版税的开放Web标准&#xff0c;用于基于OpenGL ES的低级3D图形API&#xff0c;通过HTML5 Canvas元素向ECMAScript公开。熟悉OpenGL ES 2.0的开发人员将使用GLSL将WebGL识别为基于Shader的API&#xff0c;其构造在语义上与底层Op…

FISCO BCOS(二十七)———java操作WeBase

一、搭建fiscobcos环境 1.1、安装jdk1.8 https://blog.csdn.net/weixin_46457946/article/details/1232435131.2、安装mysql https://blog.csdn.net/weixin_46457946/article/details/1232447361.3、安装python https://blog.csdn.net/weixin_46457946/article/details/123…

Lookup argument总览

1. 引言 详情参看Ingonyama团队Tomer 2023年论文《A Brief History of Lookup Arguments》。 Bootle等人2018年论文《Nearly linear-time zero-knowledge proofs for correct program execution》中首次提出了lookup协议&#xff0c;用于证明如下statement&#xff1a; 此处…

Python socket之TCP通信、下载文件

TCP简介TCP介绍TCP协议&#xff0c;传输控制协议&#xff08;英语&#xff1a;Transmission Control Protocol&#xff0c;缩写为 TCP&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议&#xff0c;由IETF的RFC 793定义。TCP通信需要经过创建连接、数据传送、…

手撕八大排序(上)

排序的概念及其引用&#xff1a; 排序的概念&#xff1a; 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有…

Linux上基于PID找到对应的进程名以及所在目录

Linux上基于PID找到对应的进程名以及所在目录前言找到进程的pid通过top命令查看通过 ps -ef |grep nignx进行查看通过端口号进行查看查看nginx进程目录前言 在一台新接触的服务器&#xff0c;却不熟悉搭建所在目录的时候&#xff0c;这时候就就可以通过ps查找进程&#xff0c;并…

巧用性格上的差异来组建团队

你好&#xff0c;我是得物 App 交易平台及中间件平台的 Team Leader Alan。 组建团队过程中&#xff0c;你有没有遇到过类似的场景&#xff1a;团队中某些人之间总是互相不对付、气场不合&#xff0c;不管是日常沟通中还是方案对齐&#xff0c;总是会出现面红耳赤的场面。 从…

Linux_线程概念

进程回顾 在学习线程之前&#xff0c;我们先回顾一下之前讲的进程概念 当我们创建一个进程&#xff0c;操作系统会将磁盘中的代码load到内存中&#xff0c;然后创建当前进程的task_struct&#xff08;后面可能会用”PCB“或者”进程控制块“代替&#xff09;&#xff0c;创建…