当前位置: 代码迷 >> 综合 >> Docker 部署 Seata Server(使用nacos 做为注册中心和配置中心)
  详细解决方案

Docker 部署 Seata Server(使用nacos 做为注册中心和配置中心)

热度:26   发布时间:2023-11-24 13:01:37.0

组件版本关系

版本说明

每个 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

(写博客主要是对自己学习的归纳整理,资料大部分来源于书籍、网络资料、官方文档和自己的实践,整理的不足和错误之处,请大家评论区批评指正。同时感谢广大博主和广大作者辛苦整理出来的资源和分享的知识。)

  相关解决方案