微服务·数据一致-seata

微服务·数据一致-seata

概述

Seata(Simple Extensible Autonomous Transaction Architecture)是一个开源的分布式事务解决方案,旨在帮助应用程序分布式事务管理的挑战。Seata提供了一套全面的工具和框架,可用于实现跨多个数据库和服务的一致性事务管理。本报告将深入探讨Seata的核心概念、架构、特性以及使用场景。

核心概念

  • 全局事务:Seata引入了全局事务的概念,将一组分支事务(通常是数据库操作)组织在一起,以确保它们要么全部成功,要么全部回滚,以维护数据的一致性。
  • 分支事务:分支事务是全局事务中的单个数据库操作或者服务调用,它们遵循全局事务的指导并协作以实现全局事务的一致性。
  • 全局事务协调器:全局事务协调器(TC,Transaction Coordinator)负责群居事务的协调和管理,确保所有分支事务按照事务的隔离级别执行。

架构

Seata的架构包括三个核心组件:

  • 全局事务协调器(TC,Transaction Coordinator):负责全局事务的协调和管理。它记录了全局事务的状态,并根据分支事务的状态来确保全局事务的最终结果。
  • 分支事务参与者(TM, Transaction Manager):负责管理和执行分支事务、包括尝试、确认和回滚分支事务(在调用服务的方法中用注解启动事务)。
  • 分支事务资源管理器(RM,Resource Manager):负责管理分支事务所涉及的资源,入数据库、消息队列、缓存等。
    Seata实现分布式事务,设计了一个关键角色UNDO_LOG(回滚日志记录表),在每个应用分布式事务的业务库中创建了这张表,这个表的的核心作用就是将业务数据在更新前后的数据镜像组成回滚日志,备份在UNDO_LOG表中,以便业务异常能随时回滚。

特性

  • 强一致性:Seata确保全局事务的强一致性,即要么全部提交成功,要么全部回滚。
  • 高性能:Seata的设计注重性能,可以处理高并发的分布式事务。
  • 分布式事务隔离:Seata支持多种隔离级别,包括串行化、可重复读等,以适应不同的业务需求。
  • 全局事务追踪:Seata提供全局事务的追踪和监控能力,有助于故障排查和性能优化。
  • 分布式事务补偿:Seata支持Saga模式,可依通过补偿事务来处理部分失败的分布式事务。

Seata AT模式的详解

以下单扣库存、扣余额举例:
在这里插入图片描述

第一阶段

在这里插入图片描述

首先Seata的JDBC数据源代理通过对业务SQL解析,提取SQL的元数据,也就是得到SQL的类型(UPDATE),表(user),条件(where name = “天青色”)等相关信息。

  • 先查询数据更改前的信息(前镜像),根据解析得到的条件信息,生成查询语句,定位一条数据。
  • 紧接着执行业务SQL,根据前镜像数据之间查询出后镜像数据
  • 把业务数据在更新前后的数据镜像组织成回滚日志,将业务数据的更新和回滚日志在同一个本地事务中提交,分别插入到业务表和UNDO_LOG表中。
    UNDO_LOG数据格式如下,包括afterImage前镜像、beforeImage后镜像、branchId分支事务ID,xid全局事务ID
{"branchId":641789253,"xid":"xid:xxx","undoItems":[{"afterImage":{"rows":[{"fields":[{"name":"id","type":4,"value":1}]}],"tableName":"product"},"beforeImage":{"rows":[{"fields":[{"name":"id","type":4,"value":1}]}],"tableName":"product"},"sqlType":"UPDATE"}]
}

这样可以保证任何提交的业务数据的更新一定有相应的回滚日志。

在本地事务提交前,各分支事务需要向TC注册分支(Branch Id),为要修改的记录申请全局锁,要为这条数据加锁,利用Select for update语句。而如果一直拿不到锁那就需要回滚本地事务。TM开启事务后会生成全局唯一的XID,会在各个调用的服务间进行传递。

有了这样的机制,本地事务分支便可以在全局事务的第一阶段提交,并马上释放本地事务锁定的资源。相比传统的XA事务在第二阶段释放资源,Seata降低了锁范围提高效率。即使第二阶段发生异常需要回滚,也可以快速从UNDO_LOG表中找到对应回滚数据并反解析成SQL来达到回滚补偿。
最后本地事务提交,业务数据的更新和前面胜澈功能的UNDO_LOG数据一并条,并将本地事务提交的结果上报给全局事务协调者TC。

第二阶段

第二阶段是根据各分支的决议作出提交或者回滚:

提交

如果决议是全局提交,此时各分支事务已提交并成功,这是全局事务协调者(TC)会向分支发送第二阶段的请求。收到TC的分支提交请求,该请求会被放入一个异步任务队列中,并马上返回提交结果返回给TC。异步队列中会异步和批量的根据BranchID查找并删除相应的UNDO_LOG回滚记录。
在这里插入图片描述

回滚

如果决议是全局回滚,RM服务放收到TC全局协调者发来的回滚请求,通过XID和Branch ID找到相应的回滚日志记录,通过回滚记录生成反向的更新SQL并执行,以完成分支的回滚。
在这里插入图片描述

读写隔离

写隔离

  • 第一阶段本地事务提交前,需要确保先拿到全局锁。
  • 拿不到全局锁,不能提交本地事务。
  • 拿全局锁的尝试会限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。

举例:两个全局事务tx1和tx2,分别对应a表的m字段更新操作,m的初始值1000。
tx1 先开始,开启本地事务,拿到本地锁,更新操作 m = 1000 - 100 = 900。本地事务提交前,先拿到该记录的 全局锁 ,本地提交释放本地锁。 tx2 后开始,开启本地事务,拿到本地锁,更新操作 m = 900 - 100 = 800。本地事务提交前,尝试拿该记录的 全局锁 ,tx1 全局提交前,该记录的全局锁被 tx1 持有,tx2 需要重试等待 全局锁 。
在这里插入图片描述
tx1 二阶段全局提交,释放 全局锁 。tx2 拿到 全局锁 提交本地事务。
在这里插入图片描述
如果 tx1 的二阶段全局回滚,则 tx1 需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。

此时,如果 tx2 仍在等待该数据的 全局锁,同时持有本地锁,则 tx1 的分支回滚会失败。分支的回滚会一直重试,直到 tx2 的 全局锁 等锁超时,放弃 全局锁 并回滚本地事务释放本地锁,tx1 的分支回滚最终成功。

因为整个过程 全局锁 在 tx1 结束前一直是被 tx1 持有的,所以不会发生 脏写 的问题。

读隔离

在数据库本地事务管理级别读已提交或以上的基础上,Seata AT模式的默认全局隔离级别是读未提交。如果在特定的场景下,必须要求全局的读已提交,seata的实现方式是通过SELECT FOR UPDATE语句代理。
在这里插入图片描述
SELECT FOR UPDATE 语句的执行会申请 全局锁 ,如果 全局锁 被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到 全局锁 拿到,即读取的相关数据是 已提交 的,才返回。

XID的传递过程

  • TM注册到TC中,要发起全局事务式,先向TC发送一个通知,然后TC就会生成一个唯一的ID返还给TM,这个ID就是xid。
  • TM收到xid后放入当前线程的ThreadLocal中存储,在业务逻辑中使用OpenFeign调用其他服务的接口时,Seata重写了feign客户端;如果是Rest Template的方式,Seata也写了请求拦截器,将当前ThreadLocal中的xid放入hreader中进行传递。
  • RM收到请求后,首先在拦截器中尝试获取header中的xid,如果获取成功,就将xid再放入当前ThreadLocal中。
  • RM通知TC自己是该xid的事务参与者,也就是注册该分支服务。

实践

Seata Server

file.conf文件用于配制持久化事务日志的模式,目前提供file、db、redis三种方式。在选择db方式后,需要在对应的数据库中闯将gloableTable(持久化全局事务)、branchTable(持久化各提交分支的事务)、lockTable(持久化各分支锁定资源事务)三张表。

-- the table to store GlobalSession data
-- 持久化全局事务
CREATE TABLE IF NOT EXISTS `global_table`
(`xid`                       VARCHAR(128) NOT NULL,`transaction_id`            BIGINT,`status`                    TINYINT      NOT NULL,`application_id`            VARCHAR(32),`transaction_service_group` VARCHAR(32),`transaction_name`          VARCHAR(128),`timeout`                   INT,`begin_time`                BIGINT,`application_data`          VARCHAR(2000),`gmt_create`                DATETIME,`gmt_modified`              DATETIME,PRIMARY KEY (`xid`),KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDBDEFAULT CHARSET = utf8;-- the table to store BranchSession data
-- 持久化各提交分支的事务
CREATE TABLE IF NOT EXISTS `branch_table`
(`branch_id`         BIGINT       NOT NULL,`xid`               VARCHAR(128) NOT NULL,`transaction_id`    BIGINT,`resource_group_id` VARCHAR(32),`resource_id`       VARCHAR(256),`branch_type`       VARCHAR(8),`status`            TINYINT,`client_id`         VARCHAR(64),`application_data`  VARCHAR(2000),`gmt_create`        DATETIME(6),`gmt_modified`      DATETIME(6),PRIMARY KEY (`branch_id`),KEY `idx_xid` (`xid`)
) ENGINE = InnoDBDEFAULT CHARSET = utf8;-- the table to store lock data
-- 持久化每个分支锁表事务
CREATE TABLE IF NOT EXISTS `lock_table`
(`row_key`        VARCHAR(128) NOT NULL,`xid`            VARCHAR(96),`transaction_id` BIGINT,`branch_id`      BIGINT       NOT NULL,`resource_id`    VARCHAR(256),`table_name`     VARCHAR(32),`pk`             VARCHAR(36),`gmt_create`     DATETIME,`gmt_modified`   DATETIME,PRIMARY KEY (`row_key`),KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDBDEFAULT CHARSET = utf8;

Seata Client

搭建服务,核心配置如下

spring:application:name: storage-servercloud:alibaba:seata:tx-service-group: my_test_tx_groupdatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://47.93.6.1:3306/seat-storageusername: rootpassword: root

业务大致流程:用户发起下单请求,本地 order 订单服务创建订单记录,并通过 RPC 远程调用 storage 扣减库存服务和 account 扣账户余额服务,只有三个服务同时执行成功,才是一个完整的下单流程。如果某个服执行失败,则其他服务全部回滚。
Seata 对业务代码的侵入性非常小,代码中使用只需用 @GlobalTransactional 注解开启一个全局事务即可。

@Override
@GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
public void create(Order order) {String xid = RootContext.getXID();LOGGER.info("------->交易开始");//本地方法orderDao.create(order);//远程方法 扣减库存storageApi.decrease(order.getProductId(), order.getCount());//远程方法 扣减账户余额LOGGER.info("------->扣减账户开始order中");accountApi.decrease(order.getUserId(), order.getMoney());LOGGER.info("------->扣减账户结束order中");LOGGER.info("------->交易结束");LOGGER.info("全局事务 xid: {}", xid);
}

在相关的业务库中创建undo_log表来存数据回滚日志,表结构如下:

-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(`id`            BIGINT(20)   NOT NULL AUTO_INCREMENT COMMENT 'increment id',`branch_id`     BIGINT(20)   NOT NULL COMMENT 'branch transaction id',`xid`           VARCHAR(100) NOT NULL COMMENT 'global transaction id',`context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',`log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',`log_created`   DATETIME     NOT NULL COMMENT 'create datetime',`log_modified`  DATETIME     NOT NULL COMMENT 'modify datetime',PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDBAUTO_INCREMENT = 1DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

结论

Seata是一个强大的分布式事务解决方案,具备高性能和强一致性的特点,适用于各种需要数据一致性的分布式应用场景。它的架构和设计使得分布式事务管理变得更加容易,有助于解决分布式系统中的一致性问题。对于需要构建高可用性和高性能的分布式应用程序的团队来说,Seata是一个值得考虑的工具和框架。

参考

https://www.cnblogs.com/chengxy-nds/p/14046856.html
https://seata.io/zh-cn/docs/next/dev/mode/at-mode

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全之认识网络安全网格架构(CSMA)

“网络安全网格(CyberSecurity Mesh)”是 Gartner 提出的网络安全技术发展新趋势,近两年连续入选其年度重要战略技术趋势研究报告,成为当前网络安全领域流行的热词,受到网络安全从业者的高度关注。 一、概念产生的背景…

软件测试/测试开发丨Web自动化 PageObject设计模式

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接:https://ceshiren.com/t/topic/27167 一、page object 模式简介 马丁福勒个人博客 selenium 官网 1.1、传统 UI 自动化的问题 无法适应 UI 频繁变化无法清晰表达业务用例场景大量的样…

python 学习笔记(5)——SMTP 使用QQ邮箱发送邮件

目录 发送邮件 1、准备工作: 2、发送纯文本信息内容: 3、发送 HTML 格式的内容: 4、发送带附件的邮件: 5、群发(一个邮件,发给多个人): 发送邮件 以下都 以 QQ邮箱 为发送方举…

Nginx+Tomcat(多实例)实现动静分离和负载均衡

一、Tomcat 多实例部署 1.在安装好jdk环境后,添加两例tomcat服务 #解压安装包 cd /opt tar zxvf apache-tomcat-9.0.16.tar.gz#移动并复制一例 mkdir /usr/local/tomcat mv apache-tomcat-9.0.16 /usr/local/tomcat/tomcat1 cp -a /usr/local/tomcat/tomcat1 /usr…

记录一次开机内存分析的全过程

作者:zzy的学习笔记 记录一次开机内存分析的全过程,尽量详尽的介绍常用内存分析工具和命令行的使用,结合具体问题探讨开机内存分析的实践经验。通过这篇文章我会介绍开机内存的常用测试分析工具的基本使用方法,以及如何通过抓取出…

在Ubuntu上建立博客网站,利用Cpolar+Inis快速实现专业写作

文章目录 前言1. Inis博客网站搭建1.1. Inis博客网站下载和安装1.2 Inis博客网站测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道(云端设置)2.3.Cpolar稳定隧道(本地设置) 3. 公网访问测试总…

springboot+redis

1.pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency> 2.yml配置 # redis 配置redis:host: 127.0.0.1#超时连接timeout: 1000msjedis:pool:#最大连…

盲打键盘的正确指法指南

简介 很多打字初学者&#xff0c;并不了解打字的正确指法规范&#xff0c;很容易出现只用两根手指交替按压键盘的“二指禅”情况。虽然这样也能实现打字&#xff0c;但是效率极低。本文将简单介绍盲打键盘的正确指法&#xff0c;以便大家在后续的学习和工作中能够提高工作效率…

Pytorch Advanced(三) Neural Style Transfer

神经风格迁移在之前的博客中已经用keras实现过了&#xff0c;比较复杂&#xff0c;keras版本。 这里用pytorch重新实现一次&#xff0c;原理图如下&#xff1a; from __future__ import division from torchvision import models from torchvision import transforms from PIL…

2024年java面试--mysql(2)

系列文章目录 2024年java面试&#xff08;一&#xff09;–spring篇2024年java面试&#xff08;二&#xff09;–spring篇2024年java面试&#xff08;三&#xff09;–spring篇2024年java面试&#xff08;四&#xff09;–spring篇2024年java面试–集合篇2024年java面试–redi…

FPGA实战小项目3

基于FPGA的波形发生器 基于FPGA的波形发生器 基于FPGA的beep音乐播放器设计 基于FPGA的beep音乐播放器设计 基于FPGA的cordic算法实现DDS sin和cosine波形的产生 基于FPGA的cordic算法实现DDS sin和cosine波形的产生

iframe 实现跨域,两页面之间的通信

一、 背景 一个项目为vue2&#xff0c;一个项目为vue3&#xff0c;两个不同的项目实现iframe嵌入&#xff0c;并实现通信 二、方案 iframe跨域时&#xff0c;iframe组件之间常用的通信&#xff0c;主要是H5的possmessage方法 三、案例代码 父页面-vue2&#xff08;端口号为…

JWT 使用教程 授权 认证

JWT 1.什么是JWT JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally s…

轻松搭建本地知识库的ChatGLM2-6B

近期发现了一个项目&#xff0c;它的前身是ChatGLM&#xff0c;在我之前的博客中有关于ChatGLM的部署过程&#xff0c;本项目在前者基础上进行了优化&#xff0c;可以基于当前主流的LLM模型和庞大的知识库&#xff0c;实现本地部署自己的ChatGPT&#xff0c;并可结合自己的知识…

Zabbix登录绕过漏洞复现(CVE-2022-23131)

0x00 前言 最近在复现zabbix的漏洞&#xff08;CVE-2022-23131&#xff09;&#xff0c;偶然间拿到了国外某公司zabbix服务器。Zabbix Sia Zabbix是拉脱维亚Zabbix SIA&#xff08;Zabbix Sia&#xff09;公司的一套开源的监控系统。该系统支持网络监控、服务器监控、云监控和…

C# Winform 简单排期实现(DevExpress TreeList)

排期的需求在很多任务安排的系统中都有相应的需求&#xff0c;原生的Winform控件并未提供相应的控件&#xff0c;一般都是利用DataGridViewTreeView组合完成相应的需求&#xff0c;实现起来比较麻烦。用过DevExpress控件集的开发者应该知道&#xff0c;DevExpress WinForm提供了…

每日一博 - CRUD system VS Event sourcing design

文章目录 概念Arch Overview小结 概念 CRUD 系统和事件溯源设计是两种不同的软件架构方法&#xff0c;用于处理数据和应用程序的状态。以下是它们的区别以及各自适用的场景&#xff1a; CRUD 系统&#xff1a; CRUD 代表 Create&#xff08;创建&#xff09;、Read&#xff08…

Android Studio实机同WIFI调试

1.点击Pair using Wi-Fi 2.手机扫描跳出来的二维码 小米手机可搜索无线调试进行adb 调试

模态分析的概念。C++减振器设计。

一、说明 模态分析是工程和物理学中用于研究系统或结构动态特性的技术。它涉及分析系统的振动或振荡的自然模式以及相应的频率、阻尼系数和振型。 在模态分析中&#xff0c;所研究的系统通常表示为一组质量、刚度和阻尼元件&#xff08;在下面的文章中忽略了阻尼&#xff09;。…

单链表(Single Link Table)——单文件实现

一、单链表前言 上篇文章我们讲述了顺序表&#xff0c;认真学习我们会发现顺序表优缺点。 缺点1&#xff1a;头部和中部的插入删除效率都不行&#xff0c;时间和空间复杂度都为O(N); 缺点2&#xff1a;空间不够了扩容有一定的消耗(尤其是realloc的异地扩容)&#xff1b; 缺…