SpringCloud(第十九章 SpringCloud Alibaba Seata处理分布式事务)

本文详细介绍了Seata分布式事务解决方案在微服务中的应用,包括Seata的安装配置、业务数据库准备、订单库存账户事务流程、以及AT模式的原理和实战演练。通过实例展示了如何解决分布式事务一致性问题和Seata组件的工作原理。
摘要由CSDN通过智能技术生成

文章目录

一、分布式事务问题

1.1 分布式前

1、单机单库没这个问题
2、 1:1(系统代码和数据库在同一台机器) -> 1:N (系统对应多个库) -> N:N(系统拆分后各自对应不同的库:比如订单模块对应订单库)
在这里插入图片描述

1.2 分布式之后

单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源,业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证,但是全局的数据一致性问题没法保证。
在这里插入图片描述

1.3 一句话

一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题。

二、Seata简介

2.1 是什么

1、Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
2、官网地址:
http://seata.io/zh-cn/

2.2 能干嘛(一个典型的分布式事务过程)

2.2.1 分布式事务处理过程的唯一ID + 三组件模型

2.2.1.1 Transaction ID XID

全局唯一的事务ID

2.2.1.2 3组件概念

1 Transaction Coordinator (TC)
事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚;
2 Transaction Manager ™
控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议;
3 Resource Manager (RM)
控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚

2.2.2 处理过程

1、TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID;
2、XID 在微服务调用链路的上下文中传播;
3、RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖;
4、TM 向 TC 发起针对 XID 的全局提交或回滚决议;
5、TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。在这里插入图片描述

2.3 去哪下

发布说明: https://github.com/seata/seata/releases

2.4 怎么玩

1、本地@Transactional
2、全局@GlobalTransactional
SEATA 的分布式交易解决方案
在这里插入图片描述

三、Seata-Server安装

3.1、官网地址

http://seata.io/zh-cn/

3.2、下载版本

https://github.com/seata/seata/releases
(本次讲解使用0.9.0版本)

3.3、修改配置文件

seata-server-0.9.0.zip解压到指定目录并
修改conf目录下的file.conf配置文件

3.3.1先备份file.conf文件

3.3.2主要修改:自定义事务组名称 + 事务日志存储模式db+数据库连接信息

3.3.3 修改file.conf配置文件

3.3.3.1 service模板
 
service {
 
  vgroup_mapping.my_test_tx_group = "fsp_tx_group"
 
  default.grouplist = "127.0.0.1:8091"
  enableDegrade = false
  disable = false
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
} 

3.3.3.2store模板
 
## transaction log store
store {
  ## store mode: file、db
  mode = "db"
 
  ## file store
  file {
    dir = "sessionStore"
 
    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    max-branch-session-size = 16384
    # globe session size , if exceeded throws exceptions
    max-global-session-size = 512
    # file buffer size , if exceeded allocate new buffer
    file-write-buffer-cache-size = 16384
    # when recover batch read size
    session.reload.read_size = 100
    # async, sync
    flush-disk-mode = async
  }
 
  ## database store
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "dbcp"
    ## mysql/oracle/h2/oceanbase etc.
    db-type = "mysql"
    driver-class-name = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://127.0.0.1:3306/seata"
    user = "root"
    password = "你自己密码"
    min-conn = 1
    max-conn = 3
    global.table = "global_table"
    branch.table = "branch_table"
    lock-table = "lock_table"
    query-limit = 100
  }
}

3.4、在mysql5.7数据库新建库seata

3.5、在新建seata库里建表

建表db_store.sql在\seata-server-0.9.0\seata\conf目录里面(db_store.sql)
在这里插入图片描述

3.6、修改seata-server-0.9.0\seata\conf目录下的registry.conf配置文件

在这里插入图片描述

3.7、启动nacos

softs\nacos-server-1.1.4\nacos\bin

3.8、再启动seata-server

softs\seata-server-0.9.0\seata\bin

四、订单/库存/账户业务数据库准备

1、以下演示都需要先启动Nacos后启动Seata,保证两个都OK
2、Seata没启动,报错no available server to connect

4.1、分布式事务业务说明

1、业务说明
在这里插入图片描述
2、下订单----> 扣库存 ----> 减账户(余额)

4.2、创建业务数据库

1、seata_order:存储订单的数据库
2、seata_storage:存储库存的数据库
3、seata_account:存储账户信息的数据库。
4、建库SQL
在这里插入图片描述

4.3、按照上述3库分别建对应业务表

4.3.1 seata_order库下建t_order表

CREATE TABLE t_order (
  `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',
  `product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',
  `count` INT(11) DEFAULT NULL COMMENT '数量',
  `money` DECIMAL(11,0) DEFAULT NULL COMMENT '金额',
  `status` INT(1) DEFAULT NULL COMMENT '订单状态:0:创建中;1:已完结' 
) ENGINE=INNODB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
 
SELECT * FROM t_order;

4.3.2 seata_storage库下建t_storage表

 
CREATE TABLE t_storage (
 `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
 `product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',
 `total` INT(11) DEFAULT NULL COMMENT '总库存',
 `used` INT(11) DEFAULT NULL COMMENT '已用库存',
 `residue` INT(11) DEFAULT NULL COMMENT '剩余库存'
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
 
 
INSERT INTO seata_storage.t_storage(`id`, `product_id`, `total`, `used`, `residue`)
VALUES ('1', '1', '100', '0', '100');
 
SELECT * FROM t_storage;
 

4.3.3 seata_account库下建t_account表

CREATE TABLE t_account (
  `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'id',
  `user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',
  `total` DECIMAL(10,0) DEFAULT NULL COMMENT '总额度',
  `used` DECIMAL(10,0) DEFAULT NULL COMMENT '已用余额',
  `residue` DECIMAL(10,0) DEFAULT '0' COMMENT '剩余可用额度'
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
 
INSERT INTO seata_account.t_account(`id`, `user_id`, `total`, `used`, `residue`)  VALUES ('1', '1', '1000', '0', '1000');
 
SELECT * FROM t_account;

4.4、按照上述3库分别建对应的回滚日志表

1、订单-库存-账户3个库下都需要建各自的回滚日志表
2、\seata-server-0.9.0\seata\conf目录下的db_undo_log.sql

建表sql

-- the table to store seata xid data
-- 0.7.0+ add context
-- you must to init this sql for you business databese. the seata server not need it.
-- 此脚本必须初始化在你当前的业务数据库中,用于AT 模式XID记录。与server端无关(注:业务数据库)
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
DROP TABLE `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=utf8;
 

4.5、最终结果

在这里插入图片描述

五、订单/库存/账户业务微服务准备

5.1、业务需求

下订单->减库存->扣余额->改(订单)状态

5.2、新建订单Order-Module

在这里插入图片描述

5.3、新建订单Storage-Module

在这里插入图片描述

5.4、新建账户Account-Module

在这里插入图片描述

六、Test

下订单->减库存->扣余额->改(订单)状态

在这里插入图片描述

6.1、数据库初始情况

SELECT * FROM seata_order.t_order
在这里插入图片描述
SELECT * FROM seata_storage.t_storage
在这里插入图片描述
SELECT * FROM seata_account.t_account;
在这里插入图片描述

6.2、正常下单

模拟地址:
http://localhost:2001/order/create?userId=1&productId=1&count=10&money=100
数据库情况
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.3、超时异常,没加@GlobalTransactional

1、AccountServiceImpl添加超时
2、数据库情况
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3、故障情况
3.1 当库存和账户金额扣减后,订单状态并没有设置为已经完成,没有从零改为1
3.2 而且由于feign的重试机制,账户余额还有可能被多次扣减

6.4、超时异常,添加@GlobalTransactional

1、AccountServiceImpl添加超时
在这里插入图片描述
2、下单后数据库数据并没有任何改变
(记录都添加不进来)

七、一部分补充

7.1、Seata

1、2019年1月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案
2、Simple Extensible Autonomous Transaction Architecture,简单可扩展自治事务框架
3、2020起始,参加工作后用1.0以后的版本
在这里插入图片描述

7.2、再看TC/TM/RM三大组件

(TC可理解为授课老师,TM是班主任,管理者学生的举动;RM是学生)
在这里插入图片描述

分布式事务执行流程:
1、TM 开启分布式事务(TM 向 TC 注册全局事务记录);
2、按业务场景,编排数据库、服务等事务内资源(RM 向 TC 汇报资源准备状态 );
3、TM 结束分布式事务,事务一阶段结束(TM 通知 TC 提交/回滚分布式事务);
4、TC 汇总事务信息,决定分布式事务是提交还是回滚;
5、TC 通知所有 RM 提交/回滚 资源,事务二阶段结束。​

7.3、AT模式如何做到对业务的无侵入

7.3.1 是什么

在这里插入图片描述

7.3.2 一阶段加载

在一阶段,Seata 会拦截“业务 SQL”,
1 解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”,
2 执行“业务 SQL”更新业务数据,在业务数据更新之后,
3 其保存成“after image”,最后生成行锁。
以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。
在这里插入图片描述

7.3.3 二阶段提交

二阶段如是顺利提交的话,
因为“业务 SQL”在一阶段已经提交至数据库,所以Seata框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。
在这里插入图片描述

7.3.4 二阶段回滚

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

7.4、补充

在这里插入图片描述

ps:尚硅谷SpringCloud学习笔记

SpringCloud(第一章 零基础理论入门)
SpringCloud(第二章 从2.2.x和H版开始说起)
SpringCloud(第三章 关于Cloud各种组件的停更/升级/替换)
SpringCloud(第四章 服务架构编码构建)
SpringCloud(第五章 Eureka服务注册与发现)
SpringCloud(第六章 Zookeeper服务注册与发现)
SpringCloud(第七章 Consul服务注册与发现)
SpringCloud(第八章 Ribbon负载均衡服务调用)
SpringCloud(第九章 OpenFeign服务接口调用)
SpringCloud(第十章 Hystrix断路器)
SpringCloud(第十一章 Gateway新一代网关)
SpringCloud(第十二章 SpringCloud Config 分布式配置中心)
SpringCloud(第十三章 SpringCloud Bus 消息总线)
SpringCloud(第十四章 SpringCloud Stream 消息驱动)
SpringCloud(第十五章 SpringCloud Sleuth 分布式请求链路跟踪)
SpringCloud(第十六章 SpringCloud Alibaba 入门简介)
SpringCloud(第十七章 SpringCloud Alibaba Nacos服务注册和配置中心)
SpringCloud(第十八章 SpringCloud Alibaba Sentinel实现熔断与限流)
SpringCloud(第十九章 SpringCloud Alibaba Seata处理分布式事务)
SpringCloud(第二十章 SpringCloud之雪花算法)

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值