目录
一、Seata+Mysql+Nacos进行部署
1、修改Seata的配置文件
2、创建数据库
3、修改registry.conf
4、nacos中添加配置文件
5、集群部署
二、分布式事务Seata的使用案例
1、分布式事务的问题引出
2、Seata实现分布式事务的案例
三、分布式的解决方案的理解
对应多进程的分布式系统来说,本地事务已不能保证数据集的一致性,由此我们可以使用Seata分布式事务来解决。
Docker安装Seata见我的这篇博客:Docker 部署微服务架构的各项环境_Dragon Wu的博客-CSDN博客_基于docker的微服务架构
本次案例基于Linux环境Seata1.3.0+Mysql8来实现
由于分布式架构需要支持集群高可用所以这里需要用到mysql。
这里我们将seata对于版本的script文件夹放入对应的目录中,便于后续使用:
seata/script at v1.3.0 · seata/seata · GitHub
进入Seata的目file.conf
修改配置如下:数据库要求必须为5.7以上版本。
数据要求5.7以上版本
运行对应版本的脚本:
seata/script/server/db at v1.3.0 · seata/seata · GitHub
-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- 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 = InnoDB
DEFAULT 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 = InnoDB
DEFAULT 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 = InnoDB
DEFAULT CHARSET = utf8;
修改nacos的配置
修改配置中心
修改script里的config.txt文件
修改为文件如下:使用db后,这里还需修改数据库的配置
如需一定机房容错可配置多个:
这里不赘述,需要使用时可以去查阅。
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=false
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
service.vgroupMapping.chengdu=default
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=false
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3308/seata_server?useUnicode=true
store.db.user=username
store.db.password=password
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
store.redis.host=127.0.0.1
store.redis.port=6379
store.redis.maxConn=10
store.redis.minConn=1
store.redis.database=0
store.redis.password=null
store.redis.queryLimit=100
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.log.exceptionRate=100
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
修改好配置,启动对应的nacos,进入script下的nacos目录,运行脚本后将会添加到nacos中
默认是本地nacos地址
也可指定命令:
sh nacos-config.sh -h 127.0.0.1 -p 8848
运行截图:
运行成功后再观察Nacos可以看到多了很多的配置文件。
可参考以下参数多次启动不同端口的seata部署即可实现集群部署。
最后在nacos服务中便可看到多个seata实例了。
可以看到seata-server已运行成功:
为了得出分布式事务所参数的问题,我模拟了以下案例进行探索。
首先,我开启了Seata服务和消费者服务、生产者服务个一台,分别注册到Nacos中:
研究思路:我通过order-service服务去调用stock-serivce服务,这两个服务均开启了@Transational本地事务看看,在本地事务的情况下,是否能保证分布式事务安全。
测试方法如下:通过order-serivce的一个接口调用后修改order表的name字段并且随之调用stock-service来对stock表的num字段进行减一的操作。
测试核心部分如下:
这里通过openFeign来远程调用stock-service的该接口:
使用ApiPost对order-serivce的该接口进行请求:
可以看到由于我设置的异常,使程序发生回滚,这时查看数据库看效果:
问题很显然了,@Transactional本地事务不能支持分布式事务的解决。
以下为AT默认模式下的案例
(1)添加核心依赖
com.alibaba.cloud
spring-cloud-starter-alibaba-seata
(2)各微服务对应数据库中添加undo_log表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (
`branch_id` bigint(20) NOT NULL COMMENT '分支事务ID',
`xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '全局事务ID',
`context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '上下文',
`rollback_info` longblob NOT NULL COMMENT '回滚信息',
`log_status` int(11) NOT NULL COMMENT '状态,0正常,1全局已完成',
`log_created` datetime(6) NOT NULL COMMENT '创建时间',
`log_modified` datetime(6) NOT NULL COMMENT '修改时间',
UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'AT transaction mode undo table' ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;
undo_log表用于做回滚的日志记录表
(3)每个微服务里添加配置如下
配置事务分组:
spring:
cloud:
alibaba:
seata:
tx-service-group: chengdu
service.vgroupMapping.chengdu=default
这里的名字为之前config.txt配置文件中你自定义的名字:
service.vgroupMapping.你自定义的名字=default
(4)每个微服务添加配置
seata:
registry:
type: nacos
nacos:
server-addr: my-server:8848 # seata server 所在的nacos服务地址
application: seata-server #seata server 的服务名seata-server,如果没有修改可以不配
username: nacos
password: WXL1214??
group: SEATA_GROUP #seata server 所在的组,默认就是SEATA_GROUP,没有改也可以
config:
type: nacos
nacos:
server-addr: my-server:8848
username: nacos
password: WXL1214??
group: SEATA_GROUP
(5)将@Transactional本地事务替换为@GlobalTransactional注解进行分布式事务调用
(6)测试
现在再来进行之前的报错测试
ApiPost进行请求后再查看数据库:
可以看到此时两个数据库都进行了回滚:
分布式事务使用成功!
来看看专家怎么说:SEATA是什么?它的四种分布式事务模式