SpringCloudAlibaba分布式事务解决方案Seata实战与源码分析-中
事务模式
概述
- 在当前的技术发展阶段,不存一个分布式事务处理机制可以完美满足所有场景的需求。一致性、可靠性、易用性、性能等诸多方面的系统设计约束,需要用不同的事务处理机制去满足。
- 目前使用的流行度情况是:AT>TCC > Saga,Seata 项目最核心的价值在于:构建一个全面解决分布式事务问题的标准化平台。基于 Seata,上层应用架构可以根据实际场景的需求,灵活选择合适的分布式事务解决方案。
- Seata针对不同的业务场景提供了四种不同的事务模式,对比如下:
- AT模式:AT 模式的一阶段、二阶段提交和回滚(借助undo_log表来实现)均由 Seata 框架自动生成,用户只需编写“业务SQL”,便能轻松接入分布式事务,AT 模式是一种对业务无任何侵入的分布式事务解决方案。
- TCC模式:相对于 AT 模式,TCC 模式对业务代码有一定的侵入性,但是 TCC 模式无 AT 模式的全局行锁,TCC 性能会比 AT模式高很多。适用于核心系统等对性能有很高要求的场景。
- SAGA模式:Sage 是长事务解决方案,事务驱动,使用那种存在流程审核的业务场景。
- XA模式:XA模式是分布式强一致性的解决方案,但性能低而使用较少。
AT模式
基础理论
使用AT模式的前提条件
- 基于支持本地 ACID 事务的关系型数据库。
- Java 应用,通过 JDBC 访问数据库。
AT模式支持的数据库有:MySQL、Oracle、PostgreSQL、 TiDB、MariaDB。
整体机制为两阶段提交协议的演变
- 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
- 二阶段:
- 提交异步化,非常快速地完成。
- 回滚通过一阶段的回滚日志进行反向补偿。
写隔离
- 一阶段本地事务提交前,需要确保先拿到 全局锁 。
- 拿不到 全局锁 ,不能提交本地事务。
- 拿 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。
读隔离
- 在数据库本地事务隔离级别 读已提交(Read Committed) 或以上的基础上,Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。
- 如果应用在特定场景下,必需要求全局的 读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。
工作机制
- 假如分支事务逻辑为:update product set name = 'GTS' where name = 'TXC'; 业务表product 表字段如下
一阶段
解析 SQL:得到 SQL 的类型(UPDATE),表(product),条件(where name = 'TXC')等相关的信息。select id, name, since from product where name = 'TXC';
查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据。前镜像为
执行业务 SQL:更新这条记录的 name 为 'GTS'。
查询后镜像:根据前镜像的结果,通过 主键 定位数据。select id, name, since from product where id = 1;后镜像为
插入回滚日志:把前后镜像数据以及业务 SQL 相关的信息组成一条回滚日志记录,插入到
UNDO_LOG
表中。提交前,向 TC 注册分支:申请
product
表中,主键值等于 1 的记录的 全局锁 。本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。
将本地事务提交的结果上报给 TC。
二阶段
- 回滚
- 收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。
- 通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。
- 数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理,详细的可去查阅官网文档。
- 根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:update product set name = 'TXC' where id = 1;
- 提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。
- 提交
- 收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。
- 异步任务阶段的分支提交请求将异步和批量地删除相应 UNDO LOG 记录。
- 回滚
实战示例
我们重新修改下上一小节seata,专门定义一个group: SEATA_GROUP,然后重新启动seata
server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${user.home}/logs/seata
extend:
logstash-appender:
destination: 127.0.0.1:4560
kafka-appender:
bootstrap-servers: 127.0.0.1:9092
topic: logback_to_logstash
console:
user:
username: seata
password: seata
seata:
config:
# support: nacos 、 consul 、 apollo 、 zk 、 etcd3
type: nacos
nacos:
server-addr: 192.168.50.95:8848
namespace: a2b1a5b7-d0bc-48e8-ab65-04695e61db01
group: SEATA_GROUP
username: nacos
password: nacos
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key: ""
#secret-key: ""
data-id: seataServer.properties
registry:
# support: nacos 、 eureka 、 redis 、 zk 、 consul 、 etcd3 、 sofa
type: nacos
preferred-networks: 30.240.*
nacos:
application: seata-server
server-addr: 192.168.50.95:8848
group: SEATA_GROUP
namespace: a2b1a5b7-d0bc-48e8-ab65-04695e61db01
#cluster: default
username: nacos
password: nacos
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key: ""
#secret-key: ""
server:
service-port: 8091 #If not configured, the default is '${server.port} + 1000'
max-commit-retry-timeout: -1
max-rollback-retry-timeout: -1
rollback-retry-timeout-unlock-enable: false
enableCheckAuth: true
retryDeadThreshold: 130000
xaerNotaRetryTimeout: 60000
recovery:
handle-all-session-period: 1000
undo:
log-save-days: 7
log-delete-period: 86400000
session:
branch-async-queue-size: 5000 #branch async remove queue size
enable-branch-async-remove: false #enable to asynchronous remove branchSession
metrics:
enabled: false
registry-type: compact
exporter-list: prometheus
exporter-prometheus-port: 9898
transport:
rpc-tc-request-timeout: 30000
enable-tc-server-batch-send-response: false
shutdown:
wait: 3
thread-factory:
boss-thread-prefix: NettyBoss
worker-thread-prefix: NettyServerNIOWorker
boss-thread-size: 1
security:
secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
tokenValidityInMilliseconds: 1800000
ignore:
urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login
我们创建订单和库存两个微服务来测试AT事务模式
- 订单服务:根据采购需求创建订单。
- 库存服务:对给定的商品扣除仓储数量。
SEATA AT 模式需要 UNDO_LOG
表,UNDO_LOG
表语句在源码目录下script\client\at\db\mysql.sql里
创建订单数据库storage,创建库存业务表storage_tbl和undo_log
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 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`
(
`branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(128) 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(6) NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
创建库存数据库order,创建订单业务表order_tbl
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 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`
(
`branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(128) 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(6) NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
引入seata依赖,由于库存微服务和订单微服务都引用ecom-commons,所以在ecom-commons的pom中添加如下seata依赖,注意这里web容器建议使用tomcat,原来我使用的是undertow,但是执行分布式事务报错所以最后注释使用undertow
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2021.1</version>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
由于使用最新版本seata-all依赖需要class字节码版本为55也即是JDK11,因此演示项目使用的JDK11,库存微服务和订单微服务微服务的启动配置文件中加入如下配置
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.50.95:8848
group: ecom-group
namespace: a2b1a5b7-d0bc-48e8-ab65-04695e61db01
username: nacos
password: nacos
# seata 配置
seata:
# 使用哪个事务组
tx-service-group: default_tx_group
service:
vgroup-mapping:
default_tx_group: default # TC 集群(必须与seata-server保持一致)
enabled: true
config:
type: nacos
nacos:
username: nacos
password: nacos
# 读取的配置分组
group: SEATA_GROUP
server-addr: 192.168.50.95:8848
namespace: a2b1a5b7-d0bc-48e8-ab65-04695e61db01
dataId: seataServer.properties
# 注册中心设置
registry:
type: nacos
nacos:
# SEATA服务中心的微服务名,此处与服务端保持一致
application: seata-server
server-addr: 192.168.50.95:8848
username: nacos
password: nacos
group: SEATA_GROUP
namespace: a2b1a5b7-d0bc-48e8-ab65-04695e61db01
订单控制器提供订单创建接口
库存控制器提供扣减库存接口
通过在订单的实现类上添加一个@GlobalTransactional注解实现分布式事务
目前是一个正常场景,访问http://localhost:4070/order/create/1000/1001/2 返回成功
库存成功扣减2个
订单表也增加一条记录
库存实现类增加异常代码
访问http://localhost:4070/order/create/1000/1001/2 返回失败
库存表没有减库存,订单表也没有新的订单记录
在订单的实现类实现类创建订单方法中去掉@GlobalTransactional后再次访问,这时候就没有分布式事务支持,再次访问后订单表有添加新的订单记录,但是库存表没有减少,至此AT事务模式的实例完整结束。
调试看过程
在订单实现类create方法和库存实现类的deduct方法入口加上端口,重新启动两个微服务
查看seata server的运行日志,出现库存和订单微服务已经注册到seata中
查看nacos服务列表,由于我启动两个订单微服务
访问http://localhost:4070/order/create/1000/1001/2 ,进入第一个断点,注意整个分布式事务不要超过超时时间默认为60秒,可以配置,我是快速截图保存
当断点走完库存返回查看几张表如下,锁表记录
分支表记录
库存表undo_log表信息如下
rollback_info信息,核心是beforeImage和afterImage
{"@class":"io.seata.rm.datasource.undo.BranchUndoLog","xid":"192.168.5.52:8091:9043512942211305791","branchId":9043512942211305793,"sqlUndoLogs":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.undo.SQLUndoLog","sqlType":"UPDATE","tableName":"storage_tbl","beforeImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"storage_tbl","rows":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Row","fields":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"id","keyType":"PRIMARY_KEY","type":4,"value":1},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"count","keyType":"NULL","type":4,"value":760}]]}]]},"afterImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"storage_tbl","rows":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Row","fields":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"id","keyType":"PRIMARY_KEY","type":4,"value":1},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"count","keyType":"NULL","type":4,"value":758}]]}]]}}]]}
订单表的undo_log表信息如下
订单表的undolog的rollback_info信息,核心是beforeImage和afterImage
{"@class":"io.seata.rm.datasource.undo.BranchUndoLog","xid":"192.168.5.52:8091:9043512942211305857","branchId":9043512942211305887,"sqlUndoLogs":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.undo.SQLUndoLog","sqlType":"INSERT","tableName":"order_tbl","beforeImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords$EmptyTableRecords","tableName":"order_tbl","rows":["java.util.ArrayList",[]]},"afterImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"order_tbl","rows":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Row","fields":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"commodity_code","keyType":"NULL","type":12,"value":"1001"},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"count","keyType":"NULL","type":4,"value":2},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"id","keyType":"PRIMARY_KEY","type":4,"value":9},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"money","keyType":"NULL","type":4,"value":20},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"user_id","keyType":"NULL","type":12,"value":"1000"}]]}]]}}]]}
XA模式
前置理论
刚性事务指的是分布式事务要像本地式事务⼀样,具备数据强⼀致性。从 CAP 来看就是要达到 CP 状态。常见的刚性事务方案有:XA 协议(2PC、JTA、JTS)、3PC。由于刚性事务同步阻塞,处理效率低,不适合⼤型⽹站分布式场景。
XA 规范是 X/Open 组织定义的分布式事务处理 (DTP,Distributed Transaction Processing) 标准。规范描述了全局的事务管理器与局部的资源管理器之间的接口。对于 XA 模型,包含三个角色:
- AP:Applicaiton,应用程序业务层,哪些操作属于⼀个事务,就是 AP 定义的。
- TM:Transaction Manager:接收 AP 的事务请求,对全局事务进⾏管理,管理事务分⽀状态,协调 RM 的处理,通知 RM 哪些操作属于哪些全局事务以及事务分⽀等等。这个也是整个事务调度模型的核⼼部分。
- RM:Resource Manager,资源管理器:⼀般是数据库,也可以是其他的资源管理器,如消息队列 (如 JMS 数据源),⽂件系统等。
XA 规范的目的是允许多个资源 (如数据库,应用服务器,消息队列等) 在同一事务中访问,这样可以使 ACID 属性跨越应用程序而保持有效。XA 规范使用两阶段提交 (2PC,Two-Phase Commit) 协议来保证所有资源同时提交或回滚任何特定的事务。目前知名的数据库,如 Oracle, DB2, mysql 等,都是实现了 XA 接口的,都可以作为 RM。
XA 规范定义了 (全局) 事务管理器 (Transaction Manager) 和 (局部) 资源管理器 (Resource Manager) 之间的接口。XA 接口是双向的系统接口,在事务管理器 (Transaction Manager) 以及一个或多个资源管理器 (Resource Manager) 之间形成通信桥梁。
XA 之所以需要引入事务管理器是因为,在分布式系统中,从理论上讲,两台机器理论上无法达到一致的状态,需要引入一个单点进行协调。事务管理器控制着全局事务,管理事务生命周期,并协调资源。资源管理器负责控制和管理实际资源 (如数据库或 JMS 队列)
XA 是数据库的分布式事务,强一致性,在整个过程中,数据一张锁住状态,即从 prepare 到 commit、rollback 的整个过程中,TM 一直把持折数据库的锁,如果有其他人要修改数据库的该条数据,就必须等待锁的释放,存在⻓事务⻛险。
为什么要在Seata中支持XA
Seata 已经支持了三大事务模式:AT、TCC、SAGA,这三个都是补偿型事务,补偿型事务处理你机制构建在 事务资源之上(要么中间件层面,要么应用层),事务资源本身对于分布式的事务是无感知的,这种对于分布式事务的无感知存在有一个根本性的问题,无法做到真正的全局一致性。
例如一个库存记录,在补偿型事务处理过程中,用80扣减为60,这个时候仓库管理员查询数据结果,看到的是60,之后因为异常回滚,库存回滚到原来的80,那么这个时候库存管理员看到的60,其实就是脏数据,而这个中间状态就是补偿型事务存在的脏数据。
和补偿型事务不同,XA协议要求事务资源 本身提供对规范和协议的支持,因为事务资源感知并参与分布式事务处理过程中,所以事务资源可以保证从任意视角对数据的访问有效隔离性,满足全局数据的一致性。
XA的价值
与 补偿型 不同,XA 协议 要求 事务资源 本身提供对规范和协议的支持。因为 事务资源 感知并参与分布式事务处理过程,所以 事务资源(如数据库)可以保障从任意视角对数据的访问有效隔离,满足全局数据一致性。比如,刚才提到的库存更新场景,XA 事务处理过程中,中间状态数据库存 50 由数据库本身保证,是不会被仓库管理员的查询统计看到的。除了 全局一致性 这个根本性的价值外,支持 XA 还有如下几个方面的好处:
- 业务无侵入:和 AT 一样,XA 模式将是业务无侵入的,不给应用设计和开发带来额外负担。
- 数据库的支持广泛:XA 协议被主流关系型数据库广泛支持,不需要额外的适配即可使用。
- 多语言支持容易:因为不涉及 SQL 解析,XA 模式对 Seata 的 RM 的要求比较少。
- 传统基于 XA 应用的迁移:传统的,基于 XA 协议的应用,迁移到 Seata 平台,使用 XA 模式将更平滑。
seata XA基础理论
前提
- 支持XA 事务的数据库。
- Java 应用,通过 JDBC 访问数据库。
整体机制
- 在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。
执行阶段
- 可回滚:业务 SQL 操作放在 XA 分支中进行,由资源对 XA 协议的支持来保证 可回滚
- 持久化:XA 分支完成后,执行 XA prepare,同样,由资源对 XA 协议的支持来保证 持久化(即,之后任何意外都不会造成无法回滚的情况)
完成阶段
- 分支提交:执行 XA 分支的 commit
- 分支回滚:执行 XA 分支的 rollback
XA模式只支持实现了XA协议的数据库。Seata支持MySQL、Oracle、PostgreSQL和MariaDB。
实战示例
XA事务模式使用和AT事务模式使用基本没有区别,我们还是用前面的例子,只需要在库存和订单微服务的配置文件中添加data-source-proxy-mode为XA,其他不变
seata:
data-source-proxy-mode: XA
XA模式不需要undo_log表,演示时我们可以先把订单和库存数据库的undo_log表删掉,为了看下xid,增加一个xid打印日志,启动订单和库存微服务,访问http://localhost:4070/order/create/2000/1001/5 ,订单微服务日志打印如下
库存微服务信息日志信息也使用XA模式,全面xid事务deduct xid:192.168.5.52:8091:9043512942211306753和订单相同
查看订单数据库已经添加订单,库存已经建库存,这个是正常场景。
在订单中添加一个异常,http://localhost:4070/order/create/2000/1001/5 显示异常,后台日志打印异常的提示
库存微服务中日志已经进行回滚,查看库存表没有减库存,订单也没有创建
TCC模式
一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:
- 一阶段 prepare 行为
- 二阶段 commit 或 rollback 行为
根据两阶段行为模式的不同,我们将分支事务划分为 Automatic (Branch) Transaction Mode 和 Manual (Branch) Transaction Mode.
TCC模式不依赖数据源(1.4.2版本及之前),1.4.2版本之后增加了TCC防悬挂措施,需要数据源支持。
AT模式是基于 支持本地 ACID 事务 的 关系型数据库
- 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
- 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
- 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
TCC 模式则不依赖于底层数据资源的事务支持,支持把 自定义 的分支事务纳入到全局事务的管理中。
- 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
- 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
- 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
案例可以参考https://github.com/seata/seata-samples ,后续再补充实战案例
Saga模式
Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。
- 使用场景
- 业务流程长、业务流程多
- 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口
- 优势
- 一阶段提交本地事务,无锁,高性能
- 事件驱动架构,参与者可异步执行,高吞吐
- 补偿服务易于实现
- 缺点
- 不保证隔离性
- Saga模式不依赖数据源。
Seata基于状态机引擎的 Saga 实现:
目前SEATA提供的Saga模式是基于状态机引擎来实现的,机制是:
- 通过状态图来定义服务调用的流程并生成 json 状态语言定义文件
- 状态图中一个节点可以是调用一个服务,节点可以配置它的补偿节点
- 状态图 json 由状态机引擎驱动执行,当出现异常时状态引擎反向执行已成功节点对应的补偿节点将事务回滚
注意: 异常发生时是否进行补偿也可由用户自定义决定
- 可以实现服务编排需求,支持单项选择、并发、子流程、参数转换、参数映射、服务执行状态判断、异常捕获等功能
Seata Saga 提供了一个可视化的状态机设计器方便用户使用,代码和运行指南请参考: https://github.com/seata/seata/tree/develop/saga/seata-saga-statemachine-designer,官方案例可以参考https://github.com/seata/seata-samples ,后续再充实战案例
**本人博客网站 **IT小神 www.itxiaoshen.com
SpringCloudAlibaba分布式事务解决方案Seata实战与源码分析-中的更多相关文章
- SpringCloudAlibaba分布式事务解决方案Seata实战与源码分析-上
概述 定义 Spring Cloud Alibaba Seata 官网地址 https://seata.io/zh-cn/ 最新版本1.5.2 Spring Cloud Alibaba Seata 文 ...
- SpringCloudAlibaba分布式流量控制组件Sentinel实战与源码分析-中
实战示例 控制台初体验 Sentinel的控制台启动后,控制台页面的内容数据都是空的,接下来我们来逐步操作演示结合控制台的使用,在上一节也已说明整合SpringCloud Alibaba第一步先加入s ...
- SpringCloudAlibaba分布式流量控制组件Sentinel实战与源码分析(上)
概述 定义 Sentinel官网地址 https://sentinelguard.io/zh-cn/index.html 最新版本v1.8.4 Sentinel官网文档地址 https://senti ...
- SpringCloudGateway微服务网关实战与源码分析 - 中
实战 路由过滤器工厂 路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应.路由过滤器的作用域是特定的路由.SpringCloud Gateway包括许多内置的GatewayFilter ...
- 从flink-example分析flink组件(3)WordCount 流式实战及源码分析
前面介绍了批量处理的WorkCount是如何执行的 <从flink-example分析flink组件(1)WordCount batch实战及源码分析> <从flink-exampl ...
- 分布式事务解决方案Seata
Seata全称是Simple Extensible Autonomous Transaction Architecture,是由阿里巴巴开源的具有高性能和易用性的分布式事务解决方案. 微服务中的分布式 ...
- 分布式事务中间件 Fescar—RM 模块源码解读
前言 在SOA.微服务架构流行的年代,许多复杂业务上需要支持多资源占用场景,而在分布式系统中因为某个资源不足而导致其它资源占用回滚的系统设计一直是个难点.我所在的团队也遇到了这个问题,为解决这个问题上 ...
- SpringCloudAlibaba注册中心与配置中心之利器Nacos实战与源码分析(上)
不断踩坑并解决问题是每个程序员进阶到资深的必要经历并以此获得满足感,而不断阅读开源项目源码和总结思想是每个架构师成长最佳途径.本篇拉开SpringCloud Alibaba最新版本实战和原理序幕,以工 ...
- 分布式事务框架-Litx补偿事务框架源码解析
前言 之前某段时间在研究分布式事务过程中,对实现原理比较好奇,于是去Gitee上找了几个人气比较高的框架进行学习,其中印象深刻的有Litx,因为Litx源码不多,且都是基于Spring和Dubbo底层 ...
随机推荐
- Linux 运维工程师面试问答录(推荐阅读)
一个执着于技术的公众号 本文整理了一些比较常见的 Linux 相关的面试题目,该问答录主要分为基础知识篇和服务器篇.内容主要涉及 Linux 基本原理.常用命令操作.服务器应用等部分的内容. Linu ...
- CVE-2021-35042
CVE-2021-35042 漏洞介绍 Django 是 Python 语言驱动的一个开源模型-视图-控制器(MVC)风格的 Web 应用程序框架. 漏洞影响版本:django 3.1.3.2 202 ...
- 批量上传文件或者上传大文件时 gateWay报错DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
一.描述 最近在批量上传文件时网关出现了异常,后面发现上传大文件也会出现文件超过256发生异常,异常信息如下: org.springframework.core.io.buffer.DataBuffe ...
- selenium模块使用详解、打码平台使用、xpath使用、使用selenium爬取京东商品信息、scrapy框架介绍与安装
今日内容概要 selenium的使用 打码平台使用 xpath使用 爬取京东商品信息 scrapy 介绍和安装 内容详细 1.selenium模块的使用 # 之前咱们学requests,可以发送htt ...
- RocketMq 完整部署
目录 RocketMq 部署 环境 物理机部署 自定义日志目录 自定义参数和数据存放位置 服务启动 启动name server 启动broker 关停服务 尝试发送消息 常见报错 部署 rockerm ...
- os模块,sys模块,json模块,subprocess模块
os模块 一·什么是os模块 os模块提供了多数操作系统的功能接口函数.当os模块被导入后,它会自适应于不同的操作系统平台,根据不同 的平台进行相应的操作,在python编程时,经常和文件.目录打交道 ...
- Mysql limit 优化优化
MySql 性能到底能有多高?用了php半年多,真正如此深入的去思考这个问题还是从前天开始.有过痛苦有过绝望,到现在充满信心! MySql 这个数据库绝对是适合dba级的高手去玩的,一般做一点1万篇新 ...
- SpringBoot从Eclipse添加的Tomcat容器中启动
SpringBoot的Web项目,想要在Eclipse中的Tomcat容器中启动运行需要做下面这两处改动 pom.xml <packaging>war</packaging> ...
- MongoDB 分片规则
每日一句 生命本身毫无意义,只有死亡才能让你邃晓人性的真谛! 每日一句 Ideal is the beacon. Without ideal, there is no secure direction ...
- 面试突击51:为什么单例一定要加 volatile?
单例模式的实现方法有很多种,如饿汉模式.懒汉模式.静态内部类和枚举等,当面试官问到"为什么单例模式一定要加 volatile?"时,那么他指的是为什么懒汉模式中的私有变量要加 vo ...