一、前言
至此,博主介绍了一些Seata环境搭建的常见坑、Seata的两种案例(SpringCloud集成Seata、SpringCloud集成Nacos + Seata):
- can not get cluster name in registry config ‘service.vgroupMapping.xx‘, please make sure registry问题解决;
- Seata Failed to get available servers: endpoint format should like ip:port 报错原因/解决方案汇总版(看完本文必解决问题)
- Seata json decode exception, Cannot construct instance of java.time.LocalDateTime报错原因/解决方案最全汇总版
- 【微服务 31】超细的Spring Cloud 整合Seata实现分布式事务(排坑版)
- 【微服务 32】Spring Cloud整合Seata、Nacos实现分布式事务案例(巨细排坑版)【云原生】
从本文开始,进入到seata源码解析系列文章;前面几篇将即AT模式为例解析Seata-Server 和 Seata-Client的交互运作流程;
在真正开始解析源码之前,我们先在IDEA中把Seata Server跑起来;
PS:前文中搭建的Seata案例,seata的版本为1.3.0,而本文开始的源码分析将基于当前(2022年8月)最新的版本1.5.2进行源码解析。
读者请根据: 【微服务 31】超细的Spring Cloud 整合Seata实现分布式事务(排坑版) 一文自行调整SpringBoot、SpringCloud、Spring Cloud Alibaba、Seata的版本(参考博文:SpringBoot、SpringCloud、SpringCloudAlibaba的版本对应关系),具体使用的版本见下一篇文章。
二、IDEA中运行Seata Server
先问自己个问题:为什么要在本地运行seata server?就博文个人感觉:seata server里面的类嵌套特别深,有时会感觉没那么必要;有一些细节点需要通过debug的方式验证推测;实践出真知!!!
本着最小依赖、验证核心功能的初衷,本文Seata Server的本地运行基于File的配置/注册方式、DB的存储数据方式;
1、把源码从Github中荡下来
源码GitHub地址:https://github.com/seata/seata/tree/v1.5.2;
通过New Project from Version Control...
的方式将源码项目拉倒本地;
选择Git代码分支:origin/1.5.2
,整体项目结构如下:
Seata Server使用到的DB
进入当前源码项目的如下目录:
在本地MySQL数据库新建数据库seata_server
,然后在其中运行mysql.sql文件,生成的表结构如下:
表的作用如下:
branch_table
用于保存分支事务数据global_table
用于保存全局事务数据lock_table
用于保存全局锁数据distributed_lock
用于保存分布式锁数据
mysql.sql如下:
-- -------------------------------- 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_status_gmt_modified` (`status` , `gmt_modified`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
-- 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 = utf8mb4;
-- the table to store lock data
CREATE 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),
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_status` (`status`),
KEY `idx_branch_id` (`branch_id`),
KEY `idx_xid_and_branch_id` (`xid` , `branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
`lock_key` CHAR(20) NOT NULL,
`lock_value` VARCHAR(20) NOT NULL,
`expire` BIGINT,
primary key (`lock_key`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);
2、调整seata-server的配置
下载并运行seata-server时,如果采用file的方式,我们需要在registry.conf
中配置seata-server的服务注册信息、file.conf
中配置seata-server的服务配置信息;
按照这个思路,以file.conf为例全局搜索(command + shift + o):file.conf;
可以看到查出了很多file.conf文件,但是很多都是在test目录下,肯定不是我们想要的;非test目录有两个file.conf文件,文件目录分别为:script/client/conf
、config/seata-config/core/src/main/resources
;又因为script/
目录是一个使用seata-server时需要的一些信息目录,所以锁定config/seata-config/core/src/main/resources
目录,然后对其做出必要修改,包括seata-server的数据存储方式采用DB。registy.conf同样操作;
运行项目后发现,配置并没有生效,因为seata-server的数据存储方式依旧采用默认的file:
seata-server
进入到seata-server目录,可以发现这是一个SpringBoot项目,其中包括了一个application.example.yml
文件;
application.example.yml
文件中部分内容如下:
这个不就是在file.conf中配置的seata-server的数据存储方式吗!我们大胆推测IDEA中本地运行seata-server时,配置信息需要写在application.yml文件中;示例内容如下:
server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${user.home}/logs/seata
console:
user:
username: seata
password: seata
seata:
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
enable-check-auth: true
enable-parallel-request-handle: true
retry-dead-threshold: 130000
xaer-nota-retry-timeout: 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
config:
# support: nacos 、 consul 、 apollo 、 zk 、 etcd3
type: file
registry:
type: file
security:
secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
tokenValidityInMilliseconds: 1800000
ignore:
urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login
store:
# support: file 、 db 、 redis
mode: db
session:
mode: db
lock:
mode: db
file:
dir: sessionStore
max-branch-session-size: 16384
max-global-session-size: 512
file-write-buffer-cache-size: 16384
session-reload-read-size: 100
flush-disk-mode: async
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata_server?rewriteBatchedStatements=true
user: root
password: 123456
min-conn: 5
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
query-limit: 100
max-wait: 5000
redis:
mode: single
database: 0
min-conn: 1
max-conn: 10
password:
max-total: 100
query-limit: 100
single:
host: 127.0.0.1
port: 6379
sentinel:
master-name:
sentinel-hosts:
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
这里有一点比较有意思:
- 如果我们没有配置seata-server通信(netty)的端口号,则默认为
${server.port} + 1000
,当然如果我们不配置,由于server.port
默认是7091,所以seata-server通信(netty)的端口号默认为8091。
3、运行seata-server
seata-server项目是一个正常的SpringBoot项目,就直接按照运行SpringBoot的方式运行其即可;
在Server
类中打个端点,验证我们对seata-server的配置是否生效;
运行结果如我们预期,seata-server的数据模式修改为了db;
三、总结和后续
IDEA中运行seata-server等价于是在本地运行一个SringBoot项目,进需把需要的配置配置在application.yml文件中即可;
后续正式开始seata的源码解析。