Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
服务编排解决分布式事务_什么是分布式事务,希望能够帮助你!!!。
Seata 是⼀款开源的分布式事务框架。致⼒于在微服务架构下提供⾼性能和简单易⽤的分布式事务服务。在 Seata 开源之前,Seata 对应的内部版本在阿⾥经济体内部⼀直扮演着分布式⼀致性中间件的⻆⾊,帮助经济体平稳的度过历年的双11,对各业务单元业务进⾏了有⼒的⽀撑。经过多年沉淀与积累,商业化产品先后在阿⾥云、⾦融云进⾏售卖。2019.1 为了打造更加完善的技术⽣态和普惠技术成果,Seata 正式宣布对外开源,未来 Seata 将以社区共建的形式帮助其技术更加可靠与完备。
官网地址:https://seata.io/zh-cn/index.html
发展历程:
seata的github地址:https://github.com/seata/seata
1. 微服务框架⽀持:⽬前已⽀持 Dubbo、Spring Cloud、Sofa-RPC、Motan 和 grpc 等RPC框架,其他框架持续集成中
2. AT模式:提供⽆侵⼊⾃动补偿的事务模式,⽬前已⽀持 MySQL、 Oracle 、PostgreSQL和 TiDB的AT模式,H2 开发中
3. TCC 模式:⽀持 TCC 模式并可与 AT 混⽤,灵活度更⾼
4. SAGA模式:为长事务提供有效的解决⽅案
5. XA 模式:⽀持已实现 XA 接⼝的数据库的 XA 模式
6. 高可用:支持基于数据库存储的集群模式,⽔平扩展能⼒强
Seata中有三⼤模块,分别是 TM、RM 和 TC。其中 TM 和 RM 是作为 Seata 的客户端与业务系统集
成在⼀起,TC 作为 Seata 的服务端独⽴部署。
TC (Transaction Coordinator) - 事务协调者:维护全局和分⽀事务的状态,驱动全局事务提交或回滚。【就是Seata Server】
TM (Transaction Manager) - 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务。【就是事务发起者】
RM (Resource Manager) - 资源管理器:管理分⽀事务处理的资源,与TC交谈以注册分⽀事务和报告分⽀事务的状态,并驱动分⽀事务提交或回滚。【所有事务的参与者】
图片来自官方
说明:在 Seata 中,分布式事务的执⾏流程:
TC 事务协调器也就是Seata Server,下载地址https://github.com/seata/seata/releases
Seata Server 要向注册中⼼进⾏注册,这样,其他服务就可以通过注册中⼼去发现 SeataServer,与 SeataServer进⾏通信。
Seata ⽀持多款注册中⼼服务:nacos 、eureka、redis、zk、consul、etcd3、sofa。
在这里演示使⽤ nacos注册中⼼,nacos服务的连接地址、注册的服务名,这需要在seata/conf/registry.conf⽂件中进行配置:
注册中心
配置中心
下载配置config.txt https://github.com/seata/seata/tree/develop/script/config-center添加到nacos,比较多。在官网的手册中https://seata.io/zh-cn/docs/user/configurations.html针对每个⼀项配置介绍。
config.txt配置文件说明:主要配置Server端存储的模式(store.mode)现有file,db,redis三种。主要存储全局事务会话信息,分⽀事务信息, 锁记录表信息,seata-server默认是file模式。file只能⽀持单机模式, 如果想要⾼可⽤模式的话可以切换db或者redis,这里采用db的方式来进行全局事务的演示。
修改config.txt配置文件:
#存储模式store.mode=db#mysql的连接信息store.db.datasource=druidstore.db.dbType=mysqlstore.db.driverClassName=com.mysql.jdbc.Driverstore.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=truestore.db.user=rootstore.db.password=adminstore.db.minConn=5store.db.maxConn=30store.db.globalTable=global_tablestore.db.branchTable=branch_tablestore.db.queryLimit=100store.db.lockTable=lock_tablestore.db.maxWait=5000 |
如果手动导入的话相当的多,这里使用官方提供的脚本进行导入到nacos配置中心
脚本下载地址:https://github.com/seata/seata/tree/develop/script/config-center/nacos
打开git bash here 执⾏nacos-config.sh。【注意这里将config.txt放到根目录下边,nacos-config.sh放到conf目录下边,操作环境是windows如果是linux直接输入命令即可。】
执行命令
sh nacos-config.sh -h 127.0.0.1
需要在你的数据库中创建一个seata的数据库,专门用于存储seata的数据信息。建表语句https://github.com/seata/seata/tree/develop/script/server/db 下载mysql的即可。
-- -------------------------------- The script used when storeMode is 'db' ---------------------------------- the table to store GlobalSession dataCREATE 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 = InnoDB DEFAULT CHARSET = utf8;-- the table to store BranchSession dataCREATE 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, `gmt_modified` DATETIME, PRIMARY KEY (`branch_id`), KEY `idx_xid` (`xid`)) ENGINE = InnoDB DEFAULT CHARSET = utf8;-- the table to store lock dataCREATE TABLE IF NOT EXISTS `lock_table`( `row_key` VARCHAR(128) NOT NULL, `xid` VARCHAR(128), `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 = InnoDB DEFAULT CHARSET = utf8; |
启动seataServer
bin/seata-server.bat
AT模式是⼀种无侵入的分布式事务解决⽅案。在AT模式下,用户只需关注⾃⼰的“业务 SQL”,⽤户
的 “业务 SQL” 作为⼀阶段,Seata 框架会⾃动⽣成事务的⼆阶段提交和回滚操作。
在介绍AT 模式的时候它是⽆侵⼊的分布式事务解决⽅案, 那么如何做到对业务的⽆侵⼊的呢?
1.⼀阶段:在⼀阶段,Seata 会拦截“业务 SQL”,⾸先解析 SQL 语义,找到“业务 SQL”要更新的业务数
据,在业务数据被更新前,将其保存成“before image”,然后执行“业务 SQL”更新业务数据,在业务数据更新之后,再将其保存成“after image”,最后生成行锁。以上操作全部在⼀个数据库事务内完成,这样保证了⼀阶段操作的原子性。
3.二阶段:
提交:⼆阶段如果是提交的话,因为“业务 SQL”在⼀阶段已经提交至数据库, 所以 Seata 框架只需将⼀阶段保存的快照数据和⾏锁删掉,完成数据清理即可。
回滚:⼆阶段如果是回滚的话,Seata 就需要回滚⼀阶段已经执行的“业务 SQL”,还原业务数据。回滚方式便是用“before image”还原业务数据;但在还原前要⾸先要校验脏写,对⽐“数据库当前业务数据”和 “after image”,如果两份数据完全⼀致就说明没有脏写,可以还原业务数据,如果不⼀致就说明有脏写,出现脏写就需要转⼈⼯处理。
AT模式的⼀阶段、⼆阶段提交和回滚均由Seata框架⾃动⽣成,⽤户只需编写“业务SQL”,便能轻松接⼊分布式事务,AT 模式是⼀种对业务⽆任何侵⼊的分布式事务解决⽅案。
TM事务管理者就是事务发起者,RM资源管理者就是事务参与者,这里就是将咱们的业务系统中添加seata。
首先在各自的业务库【所有的RM微服务】中添加undo_log表。
DDL
-- 注意此处0.3.0+ 增加唯⼀索引 ux_undo_logCREATE 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; |
TM/RM端整合seata⼀共有五个步骤
说明:事务分组有点类似于Nacos中的分组概念,分组之后有一个宕机可以快速切换到另外一个Group中。
在aiispringcloudalibaba- 2.1.0.RELEASE组件中默认使用的是0.7版本的seata版本比较低在这里更换seata的版本。
父POM中添加依赖管理
<!--seata版本管理, ⽤于锁定⾼版本的seata --> <dependency> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> <version>1.3.0</version> </dependency> 子POM中添加 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-seata</artifactId> <exclusions> <exclusion> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> </exclusion> </exclusions> </dependency> <!--seata版本管理, ⽤于锁定⾼版本的seata --> <dependency> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> </dependency>
建议:这里最好创建一个公共的依赖,直接在公共依赖中添加依赖和配置文件即可。
registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "nacos" loadBalance = "RandomLoadBalance" loadBalanceVirtualNodes = 10 nacos { application = "seata-server" serverAddr = "192.168.198.10:8848" group = "DEFAULT_GROUP" namespace = "" cluster = "default" username = "nacos" password = "nacos" } } config { # file、nacos 、apollo、zk、consul、etcd3 type = "nacos" nacos { serverAddr = "192.168.198.10:8848" namespace = "" group = "SEATA_GROUP" username = "nacos" password = "nacos" } }
#在nacos中有配置spring: cloud: alibaba: seata: tx-service-group: my_test_tx_group#日志输出级别logging: level: io: seata: debug |
注意:我是在公共模块的application-seata.yml配置文件中添加的配置,需要在各个RM和TM中激活这个配置文件
profiles: active: seata
@Configuration public class DataSourceConfig { /** * 使⽤druid连接池 */ @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource() { return new DruidDataSource(); } @Primary //设置⾸选数据源对象 @Bean("dataSource") public DataSourceProxy dataSource(DataSource druidDataSource) { return new DataSourceProxy(druidDataSource); } } 启动扫描配置类,分别加载每个⼯程的启动类中 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @Import(DataSourceConfig.class)
在TM业务方法上贴上@GlobalTransactional
1)在TM和RM中配置registry.conf的时候,没有写application导致没办法跟seataServer通信
2)在TM模块如果引入公共模块的话也需要激活
Seata 开源了 TCC 模式,该模式由蚂蚁⾦服贡献。TCC 模式需要⽤户根据⾃⼰的业务场景实现Try、Confirm 和 Cancel 三个操作;事务发起⽅在⼀阶段 执⾏ Try ⽅式,在⼆阶段提交执⾏ Confirm⽅法,⼆阶段回滚执⾏ Cancel ⽅法。http://seata.io/zh-cn/docs/overview/what-is-seata.html 官网参考文档。
TCC 三个⽅法描述:
用户接⼊ TCC ,最重要的是考虑如何将⾃⼰的业务模型拆成两阶段来实现。
以“扣钱”场景为例,在接⼊ TCC 前,对A账户的扣钱,只需⼀条更新账户余额的 SQL 便能完成;但是在接⼊ TCC 之后,⽤户就需要考虑如何将原来⼀步就能完成的扣钱操作,拆成两阶段,实现成三个⽅法,并且保证⼀阶段 Try 成功的话 ⼆阶段 Confirm ⼀定能成功。
Try 方法作为⼀阶段准备⽅法,需要做资源的检查和预留。在扣钱场景下,Try 要做的事情是就是检查账户余额是否充⾜,预留转账资⾦,预留的⽅式就是冻结 A 账户的 转账资⾦。Try ⽅法执⾏之后,账号 A 余额虽然还是 100,但是其中 30 元已经被冻结了,不能被其他事务使⽤。
⼆阶段 Confirm ⽅法执⾏真正的扣钱操作。Confirm 会使⽤ Try 阶段冻结的资⾦,执⾏账号扣款。Confirm 方法执行之后,账号 A 在⼀阶段中冻结的 30 元已经被扣除,账号 A 余额变成 70 元 。
如果⼆阶段是回滚的话,就需要在 Cancel ⽅法内释放⼀阶段 Try 冻结的 30 元,使账号 A 的回到初始状态,100 元全部可用。
用户接入TCC 模式,最重要的事情就是考虑如何将业务模型拆成2阶段,实现成 TCC 的 3 个⽅法,并且保证 Try 成功 Confirm ⼀定能成功。相对于 AT 模式,TCC模式对业务代码有⼀定的侵⼊性,但是 TCC 模式⽆ AT 模式的全局行锁,TCC 性能会⽐ AT 模式高很多。
针对RM端,实现起来需要完成try/commit/rollback的实现,所以步骤相对较多但是前三步骤和AT模式⼀样
不同的是TCC模式不在使用全局代理数据源,而是直接对业务代码进行改造。
/** * @LocalTCC 该注解需要添加到上⾯描述的接⼝上,表示实现该接⼝的类被 seata 来管理,seata 根据事务的状态, * ⾃动调⽤我们定义的⽅法,如果没问题则调⽤ Commit ⽅法,否则调⽤ Rollback ⽅法。 */ @LocalTCC public interface OrderService { /** * @TwoPhaseBusinessAction 描述⼆阶段提交 * name: 为 tcc⽅法的 bean 名称,需要全局唯⼀,⼀般写⽅法名即可 * commitMethod: Commit⽅法的⽅法名 * rollbackMethod:Rollback⽅法的⽅法名 * @BusinessActionContextParamete 该注解⽤来修饰 Try⽅法的⼊参, * 被修饰的⼊参可以在 Commit ⽅法和 Rollback ⽅法中通过BusinessActionContext 获取。 */ @TwoPhaseBusinessAction(name = "addTcc", commitMethod = "addCommit", //提交代码 rollbackMethod ="addRollBack"//回滚代码 ) void add(@BusinessActionContextParameter(paramName = "order") Orders order); /** * 提交代码 * 入参必须是BusinessActionContext */ boolean addCommit(BusinessActionContext context); /** * 添加回滚代码 * 入参必须是BusinessActionContext */ boolean addRollBack(BusinessActionContext context); }
实现类
@Service public class OrderServiceImpl implements OrderService { @Override public void add(Orders order) { //执行保存 //重点是需要在业务表中添加字段 来表明是事务未提交的中间状态 } @Override public boolean addCommit(BusinessActionContext context) { ///这个key就是 接口中的入参的key Object jsonOrder = context.getActionContext("order"); Object order = JSON.parseObject(jsonOrder.toString(), Orders.class); //todo 修改中间状态,并且可以执行一些成功的业务逻辑 //返回true代表执行成功 return true; } @Override public boolean addRollBack(BusinessActionContext context) { //todo 执行回滚逻辑 //返回true 代表执行成功 return true; } }
其他的RM资源微服务也需要按照这样子去修改。
TCC模式相比AT模式的话,TCC需要对业务代码进行侵入,并且需要对业务表添加中间状态。
TCC模式难点是将业务拆分成二阶段提交。
TCC模式的优点也和明显是没有全局行锁,效率比较高。
Saga 模式是 Seata 开源的长事务解决⽅案,将由蚂蚁⾦服主要贡献。在 Saga 模式下,分布式事务内有多个参与者,每⼀个参与者都是⼀个冲正补偿服务,需要⽤户根据业务场景实现其正向操作和逆向回滚操作。
分布式事务执⾏过程中,依次执行各参与者的正向操作,如果所有正向操作均执⾏成功,那么分布式事务提交。如果任何一个正向操作执行失败,那么分布式事务会去退回去执⾏前⾯各参与者的逆向回滚操作,回滚已提交的参与者,使分布式事务回到初始状态。
适⽤场景:
模式 |
集成难度 |
隔离性 |
推荐度 |
数据库改造 |
实现机制 |
场景 |
AT |
低 |
保证 |
⾼ |
UNDO_LOG |
DataSource代理 |
⾃研项⽬全场景、拥有数据访问权限、快速集成场景 |
TCC |
⾮常⾼ |
保证 |
中 |
⽆ |
TCC实现 |
更⾼的性能要求、更复杂的场景 |
Sage |
中等 |
不保证 |
低 |
流程与实例表 |
状态机 |
⻓流程、涉及⼤量第三⽅调⽤ |
AT 模式是⽆侵⼊的分布式事务解决⽅案,适⽤于不希望对业务进⾏改造的场景,⼏乎0学习成本。
TCC 模式是⾼性能分布式事务解决⽅案,适⽤于核⼼系统等对性能有很⾼要求的场景。
Saga 模式是⻓事务解决⽅案,适⽤于业务流程⻓且需要保证事务最终⼀致性的业务系统,Saga 模式⼀阶段就会提交本地事务,⽆锁,⻓流程情况下可以保证性能,多⽤于渠道层、集成层业务系统。事务参与者可能是其它公司的服务或者是遗留系统的服务,⽆法进⾏改造和提供 TCC 要求的接⼝,也可以使⽤Saga 模式。
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
上一篇
已是最后文章
下一篇
已是最新文章