官方文档:https://seata.io/zh-cn/
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
Seata 是阿里开源的分布式事务框架,属于二阶段提交模式。
TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。
TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。
RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
单体应用架构
微服务应用架构
Seate处理事务流程
两阶段提交协议的演变:
一阶段(1~4)
二阶段-回滚(5~7)
二阶段-提交(8)
@GlobalTransactional
)来说明他是一个全局事务,这时他的角色为 TM(事务管理者)UNDO_LOG
表中。向 TC 注册分支, 申请全局锁,拿到锁后提交本地事务,将本地事务提交的结果上报给 TC。 Storage 的角色是 RM(资源管理者),管理分支事务处理的资源。下载地址:https://github.com/seata/seata/releases
#解压到指定文件夹
tar -zxvf ./seata-server-1.3.0.tar.gz -C /sunny/software/
下载地址:https://github.com/seata/seata/tree/1.3.0/script
目录结构
#存放client端sql脚本 (包含 undo_log表) ,参数配置
client
#各个配置中心参数导入脚本,config.txt(包含server和client,原名nacos-config.txt)为通用参数文件
config-center
#server端数据库脚本 (包含 lock_table、branch_table 与 global_table) 及各个容器配置
server
client
需要客户端 添加undo_log表
config-center
将
config-center
目录下的config.txt
放到seata安装目录下,nacos-config.sh
放到seata bin目录下server
Mysql创建数据库seata,执行server目录下的sql脚本,创建表lock_table、branch_table 与 global_table。
cd /sunny/software/seata/conf/
#这里采用的Nacos的服务注册与用户中心 所以不需要修改file.conf 只需要修改registry.conf 填写Nacos相关配置
vim ./registry.conf
#修改注册配置
registry{
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
application = "seata-server"
serverAddr = "127.0.0.1:8848"
group = "SEATA_GROUP"
namespace = "e90d261b-9c05-4bcb-b99f-b419d952737a"
cluster = "default"
username = "nacos"
password = "nacos"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "127.0.0.1:8848"
namespace = "e90d261b-9c05-4bcb-b99f-b419d952737a"
group = "SEATA_GROUP"
username = "nacos"
password = "nacos"
}
}
config.txt
和nacos-config.sh
修改config.txt
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.sunnyws-seata-order-group=default
service.vgroupMapping.sunnyws-seata-storage-group=default
service.default.grouplist=172.16.220.50: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.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
store.mode=file
store.publicKey=
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionSize=512
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
store.file.sessionReloadReadSize=100
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://172.16.220.50:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=root
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.mode=single
store.redis.single.host=127.0.0.1
store.redis.single.port=6379
store.redis.maxConn=10
store.redis.minConn=1
store.redis.maxTotal=100
store.redis.database=0
store.redis.password=
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.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
log.exceptionRate=100
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
推送配置
#-h -p 指定nacos的端口地址;
#-g 指定配置的分组,注意,是配置的分组;
#-t 指定命名空间id;
#-u -w指定nacos的用户名和密码
#需要已经启动Nacos
sh nacos-config.sh -h 127.0.0.1 -p 8848 -g SEATA_GROUP -t e90d261b-9c05-4bcb-b99f-b419d952737a -u nacos -w nacos
#示例
[root@localhost bin]# sh nacos-config.sh -h 127.0.0.1 -p 8848 -g SEATA_GROUP -t e90d261b-9c05-4bcb-b99f-b419d952737a -u nacos -w nacos
set nacosAddr=127.0.0.1:8848
set group=SEATA_GROUP
Set transport.type=TCP successfully
Set transport.server=NIO successfully
Set transport.heartbeat=true successfully
Set transport.enableClientBatchSendRequest=false successfully
Set transport.threadFactory.bossThreadPrefix=NettyBoss successfully
Set transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker successfully
Set transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler successfully
Set transport.threadFactory.shareBossWorker=false successfully
Set transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector successfully
Set transport.threadFactory.clientSelectorThreadSize=1 successfully
Set transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread successfully
Set transport.threadFactory.bossThreadSize=1 successfully
Set transport.threadFactory.workerThreadSize=default successfully
Set transport.shutdown.wait=3 successfully
Set service.vgroupMapping.my_test_tx_group=default successfully
Set service.default.grouplist=127.0.0.1:8091 successfully
Set service.enableDegrade=false successfully
#-h: 注册到注册中心的ip
#-p: Server rpc 监听端口
#-m: 全局事务会话信息存储模式,file、db、redis,优先读取启动参数 (Seata-Server 1.3及以上版本支持redis)
#-n: Server node,多个Server时,需区分各自节点,用于生成不同区间的transactionId,以免冲突
#-e: 多环境配置参考 http://seata.io/en-us/docs/ops/multi-configuration-isolation.html
#前台启动
seata-server.sh -h 172.16.220.50 -p 8091 -m db -n 1
#后台启动
nohup ./seata-server.sh -h 172.16.220.50 -p 8091 -m db -n 1 > ./nohuo.out 2>&1 &
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>io.seatagroupId>
<artifactId>seata-spring-boot-starterartifactId>
<version>1.4.1version>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-seataartifactId>
<exclusions>
<exclusion>
<groupId>io.seatagroupId>
<artifactId>seata-spring-boot-starterartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
引入数据库进行测试
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>${mybatis-plus.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>${druid.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
<scope>runtimescope>
dependency>
server:
port: 8002
spring:
application:
name: sunnyws-seata-order
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: 172.16.220.50:8848
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://172.16.220.50:3306/seata_order?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT&allowPublicKeyRetrieval=true
username: root
password: root
seata:
enabled: true
application-id: ${spring.application.name} # seata 应用编号,默认为 ${spring.application.name}
tx-service-group: sunnyws-seata-order-group # seata 事务组编号,用于 TC 集群名
# seata 服务配置项,对应 ServiceProperties 类
service:
grouplist:
default: 172.16.220.50:8091
# 虚拟组和分组的映射, key一定要与 my_test_tx_group一致
vgroupMapping:
sunnyws-seata-order-group: default
#不禁用全局事务
disable-global-transaction: false
@GlobalTransactional
注解将本地@Transactional
去除后,可以在异常抛出前看到订单和库存都已更新到数据库,并且客户端数据库undo_log
表和seata服务端数据global_table
表都生成了记录,xid也都相同。
当放开断点,抛出异常后,订单和库存也都回到之前的数据,undo_log和服务端的事务记录也被删除掉了。
作者: SunnyWs
链接: https://sunnyws.com/posts/7a1077b7/
来源: SunnyWs’Blog