组件版本关系
版本说明
每个 Spring Cloud Alibaba 版本及其自身所适配的各组件对应版本(经过验证,自行搭配各组件版本不保证可用)如下表所示(最新版本用*标记):
docker 拉取 seata镜像
seata github地址 seata目前已经维护到了1.4.2
seata 手动下载地址
因为和其他组件适配的关系,我使用docker部署1.3.0的seata
docker pull seataio/seata-server:1.3.0
创建挂载文件夹
mkdir -p /usr/local/seata/config
赋予权限
chmod -R 777 /usr/local/seata
seata 配置的脚本文件地址
放入了一系列的配置文件的脚本文件,大家可以自行查阅,也可以直接将seata的整个包下载下来
使用自定义配置文件
自定义配置文件需要通过挂载文件的方式实现,将宿主机上的 registry.conf 和 file.conf 挂载到容器中相应的目录(本博客只用挂载registry.conf 文件,file.conf文件的内容保存到nacos-server里面)
registry.conf
用于指定注册中心和配置中心的配置文件。如果是单机的seata server,采用注册中心和配置中心都采用file模式比较好,意思就是这些信息都会保存在本地,性能是比较好的。但如果要部署seata server集群,就引入其他组件来做注册中心和配置中心会比较方便。
如果需要同时指定 file.conf 配置文件,则需要在 registry.conf 文件中将 config 配置改为以下内容,name 的值为容器中对应的路径。从本地读取配置信息。
配置信息也可以放在配置中心上面(本博客是部署到nacos上面,这里只是做一个介绍,配置文件不用像下面这么指定,因为不会使用本地文件)
config {
type = "file"file {
name = "file:/root/seata-config/file.conf"}
}
文件如下所示,注册中心和配置中心都使用nacos
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofatype = "nacos"loadBalance = "RandomLoadBalance"nacos {
application = "seata-server"serverAddr = "IP:8848"group = "SEATA_GROUP"namespace = "" # 用来做资源隔离的cluster = "default"username = "nacos"password = "nacos"}eureka {
serviceUrl = "http://localhost:8761/eureka"weight = "1"}redis {
serverAddr = "localhost:6379"db = "0"password = ""timeout = "0"}zk {
serverAddr = "127.0.0.1:2181"sessionTimeout = 6000connectTimeout = 2000username = ""password = ""}consul {
serverAddr = "127.0.0.1:8500"}etcd3 {
serverAddr = "http://localhost:2379"}sofa {
serverAddr = "127.0.0.1:9603"region = "DEFAULT_ZONE"datacenter = "DefaultDataCenter"group = "SEATA_GROUP"addressWaitTime = "3000"}file {
name = "file:/root/seata-config/file.conf"}
}config {
# file、nacos 、apollo、zk、consul、etcd3、springCloudConfigtype = "nacos"nacos {
serverAddr = "IP:8848"namespace = ""group = "SEATA_GROUP"cluster = "default"username = "nacos"password = "nacos"}consul {
serverAddr = "127.0.0.1:8500"}apollo {
appId = "seata-server"apolloMeta = "http://192.168.1.204:8801"namespace = "application"}zk {
serverAddr = "127.0.0.1:2181"sessionTimeout = 6000connectTimeout = 2000username = ""password = ""}etcd3 {
serverAddr = "http://localhost:2379"}file {
name = "file:/root/seata-config/file.conf"}
}
file.conf 配置文件
用于指定数据存储的配置文件(当我们把配置信息写入到nacos的时候,这个本地的配置文件已经不需要了,不过这里还是简单介绍一下)
因为TC需要进行全局事务和分支事务的记录,所以需要对应的存储。
Server端存储模式(store.mode) 支持三种:
- file:单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高(默认)
- db:(mysql 需要5.7以上的版本,我的mysql是部署的8)高可用模式,全局事务会话信息通过db共享,相应性能差些
- redis: Seata-Server 1.3及以上版本支持,性能较高,存在事务信息丢失风险,请提前配置适合当前场景的redis持久化配置
我这里采用db存储,自己修改mysql 的连接信息
## transaction log store, only used in seata-server
store {
## store mode: file、db、redismode = "db"## file store propertyfile {
## store location dirdir = "sessionStore"# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptionsmaxBranchSessionSize = 16384# globe session size , if exceeded throws exceptionsmaxGlobalSessionSize = 512# file buffer size , if exceeded allocate new bufferfileWriteBufferCacheSize = 16384# when recover batch read sizesessionReloadReadSize = 100# async, syncflushDiskMode = async}## database store propertydb {
## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.datasource = "druid"## mysql/oracle/postgresql/h2/oceanbase etc.dbType = "mysql"driverClassName = "com.mysql.jdbc.Driver"url = "jdbc:mysql://IP:3306/seata_server"user = "mysql"password = "mysql"minConn = 5maxConn = 30globalTable = "global_table"branchTable = "branch_table"lockTable = "lock_table"queryLimit = 100maxWait = 5000}## redis store propertyredis {
host = "127.0.0.1"port = "6379"password = ""database = "0"minConn = 1maxConn = 10queryLimit = 100}
}
mysql 部署
建库seata_server ,用来保存事务信息
CREATE DATABASE seata_server;
sql脚本地址
mysql.sql 建表的sql 文件
有三个表
- global_table(全局事务): 每当有一个全局事务发起后,就会在该表中记录全局事务的ID和信息。
- branch_table(分支事务): 记录每一个分支事务的ID,分支事务操作的哪个数据库等信息
- lock_table(全局锁):用于申请全局锁。存储锁的相关信息,比如锁的是那张表等等
-- -------------------------------- 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 = InnoDBDEFAULT 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 = InnoDBDEFAULT CHARSET = utf8;-- 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`)
) ENGINE = InnoDBDEFAULT CHARSET = utf8;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 = InnoDBDEFAULT CHARSET = utf8mb4;INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('HandleAllSession', ' ', 0);
使用nacos 保存 seata server的配置信息
示例配置文件地址
所有的配置信息都在这个地址的config.txt文件里面,都是默认配置
我们针对我们的设置做一点修改
store.mode默认为file,我这里修改成db。自己的mysql的相关信息自己修改
store.mode:把store.mode=file 改为 store.mode=db 代表采用数据库存储Seata-Server的全局事务数据store.db.driverClassName:驱动根据mysql版本做相应修改,8.0以上用com.mysql.cj.jdbc.Driver,8.0以下用com.mysql.jdbc.Driverstore.db.url:数据库连接地址
store.db.user:数据库用户名
store.db.password:数据库密码
我的mysql是8,所以
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://IP:3306/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
配置事务分组的信息:是为了异地容灾而出现的,集群里面有多个事务分组,分布在不同的城市
service.vgroupMapping.changsha_tx_group=default 要和registry.conf配置文件的cluster对应,这里为default
service.default.grouplist=127.0.0.1:8091 当注册中心为file的时候,这个配置才有用,因为这个时候会读取配置文件得知seata-server服务的地址在那
当注册中心为其他组件时,他会从注册中心得知seata-server服务的地址,而非从配置文件得知(这个是我结合实践猜想的,如果大家有不同见解,请大家指教)
service.vgroupMapping.changsha_tx_group=default
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
使用脚本文件nacos-config.sh 将本地配置文件推送到nacos上面
#!/usr/bin/env bash
# Copyright 1999-2019 Seata.io Group.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at、
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.while getopts ":h:p:g:t:u:w:" opt
docase $opt inh)host=$OPTARG;;p)port=$OPTARG;;g)group=$OPTARG;;t)tenant=$OPTARG;;u)username=$OPTARG;;w)password=$OPTARG;;?)echo " USAGE OPTION: $0 [-h host] [-p port] [-g group] [-t tenant] [-u username] [-w password] "exit 1;;esac
doneif [[ -z ${host} ]]; thenhost=localhost
fi
if [[ -z ${port} ]]; thenport=8848
fi
if [[ -z ${group} ]]; thengroup="SEATA_GROUP"
fi
if [[ -z ${tenant} ]]; thentenant=""
fi
if [[ -z ${username} ]]; thenusername=""
fi
if [[ -z ${password} ]]; thenpassword=""
finacosAddr=$host:$port
contentType="content-type:application/json;charset=UTF-8"echo "set nacosAddr=$nacosAddr"
echo "set group=$group"failCount=0
tempLog=$(mktemp -u)
function addConfig() {
curl -X POST -H "${contentType}" "http://$nacosAddr/nacos/v1/cs/configs?dataId=$1&group=$group&content=$2&tenant=$tenant&username=$username&password=$password" >"${tempLog}" 2>/dev/nullif [[ -z $(cat "${tempLog}") ]]; thenecho " Please check the cluster status. "exit 1fiif [[ $(cat "${tempLog}") =~ "true" ]]; thenecho "Set $1=$2 successfully "elseecho "Set $1=$2 failure "(( failCount++ ))fi
}count=0 #读取上一级文件夹里面的config.txt 文件
for line in $(cat $(dirname "$PWD")/config.txt | sed s/[[:space:]]//g); do(( count++ ))key=${line%%=*}value=${line#*=}addConfig "${key}" "${value}"
doneecho "========================================================================="
echo " Complete initialization parameters, total-count:$count , failure-count:$failCount "
echo "========================================================================="if [[ ${failCount} -eq 0 ]]; thenecho " Init nacos config finished, please start seata-server. "
elseecho " init nacos config fail. "
fi
注意:仔细看脚本里面的代码,是读取上一级别文件路径下的config.txt文件,然后写入nacos-server, 是写死的 。
所以我们要把这个包下载下来
找一个能执行脚本文件的终端,我这里使用git的终端
sh nacos-config.sh -h 81.68.82.48 -p 8848 -g SEATA_GROUP -t xxx
参数说明:
-h: host,默认值localhost
-p: port,默认值8848
-g:配置分组,默认值为’SEATA_GROUP’
-t:租户信息,对应Nacos的命名空间ID字段,默认值为空
访问nacos-server 的UI页面,已经可以看见配置信息已经写入nacos了
环境变量
seata-server 支持以下环境变量:
- SEATA_IP: 可选, 指定seata-server启动的IP, 该IP用于向注册中心注册时使用, 如eureka等
- SEATA_PORT: 可选, 指定seata-server启动的端口, 默认为 8091
- STORE_MODE: 可选, 指定seata-server的事务日志存储方式, 支持db ,file,redis(Seata-Server 1.3及以上版本支持), 默认是 file
- SERVER_NODE: 可选, 用于指定seata-server节点ID, 如 1,2,3…, 默认为 根据ip生成
- SEATA_ENV: 可选, 指定 seata-server 运行环境, 如 dev, test 等, 服务启动时会使用 registry-dev.conf 这样的配置
- SEATA_CONFIG_NAME: 可选, 指定配置文件位置, 如 file:/root/registry, 将会加载 /root/registry.conf 作为配置文件,如果需要同时指定 file.conf文件,需要将registry.conf的config.file.name的值改为类似file:/root/file.conf:
创建运行容器
将registry.conf 配置文件通过xftp软件移动到宿主机的挂载文件夹下
使用自定义配置文件时必须指定环境变量 SEATA_CONFIG_NAME, 并且值需要以file:开始, 如: file:/root/seata-config/registry
docker run -itd --name seata-server \-p 8091:8091 \-e SEATA_CONFIG_NAME=file:/root/seata-config/registry \-e SEATA_IP=宿主机IP \-v /usr/local/seata/config:/root/seata-config \seataio/seata-server:1.3.0
其中 -e 用于配置环境变量, -v 用于挂载宿主机的目录
使用nacos 做为注册中心,还是指定宿主机的IP比较好,不然就会出现这篇博客的情况
spring cloud 集成seata的时候:can not register RM,err:can not connect to services-server.
容器命令行及查看日志
docker exec -it seata-server sh
docker logs -f seata-server
对外开放端口
firewall-cmd --permanent --add-port=8091/tcp
重启防火墙(修改配置后要重启防火墙)
firewall-cmd --reload
还需要去服务器的控制台去开启防火墙,
如果是阿里云,还需要在安全组里面手动添加端口 ,配置可由那些IP访问。
查看nacos 的注册服务列表
References:
- https://seata.io/zh-cn/docs/ops/deploy-by-docker.html
- https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
- https://blog.csdn.net/weixin_42105432/article/details/107746420
- https://blog.csdn.net/weixin_38106322/article/details/122246569
- https://www.cnblogs.com/hanby/p/15514393.html
(写博客主要是对自己学习的归纳整理,资料大部分来源于书籍、网络资料、官方文档和自己的实践,整理的不足和错误之处,请大家评论区批评指正。同时感谢广大博主和广大作者辛苦整理出来的资源和分享的知识。)