侧边栏壁纸
博主头像
林雷博主等级

斜月沉沉藏海雾,碣石潇湘无限路

  • 累计撰写 132 篇文章
  • 累计创建 47 个标签
  • 累计收到 3 条评论

目 录CONTENT

文章目录

13、Seata-分布式解决方案

林雷
2020-03-27 / 0 评论 / 0 点赞 / 696 阅读 / 17,073 字

一 Seata原理

1.1 Seata简介

Seata是阿里巴巴开源的分布式事务中间件,一种分布式事务解决方案,具有高性能和易于使用的微服务架构,致力于提供高性能和简单易用的分布式事务服务。Seata提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式事务解决方案。

1.1.1 Seata术语

  • TC:事务协调者,维护全局和分支事务的状态,驱动全局事务提交和回滚
  • TM:事务管理器,定义全局事务的范围:开始全局事务、提交或回滚全局事务
  • RM:资源管理器,管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交和回滚

1.2 Seata事务模式

1.2.1 Seata AT模式

AT,Automatic Transaction模式,AT模式下,把每个数据库当做是一个Resource,Seata里称为DataSource Resource。业务通过JDBC标准接口访问数据库资源时,Seata框架对所有请求进行拦截,做一些操作。每个本地事务提交时,Seata RM(Resource Manager,资源管理器)都会向TC注册一个分支事务。当请求链路调用完成后,发起方通知TC提交或回滚分布式事务,进入二阶段调用流程。
此时,TC会根据之前注册的分支事务回调到对应参与者去执行对应资源的第二阶段。TC是通过资源的全局唯一的资源ID,并且在初始化时用该ID向TC注册资源,正确找到对应的资源。

Seata AT模式的整体机制可以总结为:两阶段提交协议的演变

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源
  • 二阶段:
    • 提交异步化,非常快速的完成
    • 回滚通过一阶段的回滚日志进行反向补偿

Seata AT模式的特性有:

  • 写隔离
  • 读隔离

1.2.1.1 写隔离

  • 一阶段本地事务提交前,需要确保先拿到全局锁
  • 拿不到全局锁,不能提交本地事务
  • 拿全局锁的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁

举一个例子,如下图所示:
1-f7d97573

两个全局事务tx1和tx2,分别对a表的m字段进行更新操作,m的初始值为1000。

tx1先开始,开启本地事务,拿到本地锁,更新m = 1000 - 100 = 900。本地事务提交前,先拿到该事务的全局锁,本地提交释放本地锁。tx2后开始,开启本地事务,拿到本地锁,更新操作 m = 900 - 100 = 800。本地事务提交前,尝试拿该记录的全局锁,tx1全局提交前,该记录的全局锁被tx1持有,tx2需要重试等待全局锁。

tx1 二阶段全局提交,释放全局锁,tx2拿到全局锁提交本地事务,如下图所示:
image-cc3084af

如果tx1的二阶段全局回滚,则tx1需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。

此时,如果tx2仍在等待该数据的全局锁,同时持有本地锁,则tx1的分支回滚会失败。分支的回滚会一直重试,直到tx2的全局锁超时,放弃全局锁并回滚本地事务释放本地锁,tx1的分支回滚最终成功。
因为整个过程全局锁在tx1结束前一直被tx1持有,所以不会发生脏写的问题。

1.2.1.2 读隔离

在数据库本地事务隔离级别为读已提交(Read Committed)或以上的基础上,Seata AT模式的默认全局隔离级别是读未提交(Read Uncommitted)。
如果应用在特定场景下,必须要求全局的读已提交,目前Seata的方式是通过SELECT FOR UPDATE语句的代理。

1.2.1.3 工作机制

以一个示例来说明整个AT分支的工作过程。
业务表:product

CREATE TABLE `product` (
  `id` bigint(20) NOT NULL COMMENT '主键ID',
  `name` varchar(100) DEFAULT NULL COMMENT '名称',
  `since` varchar(100) DEFAULT NULL COMMENT '位置',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

AT分支事务的业务逻辑如下:

UPDATE product SET name = 'GTS' WHERE name = 'TXC';
1.2.1.3.1 一阶段

过程如下:

  • 解析SQL:得到的SQL类型(UPDATE),表(product),条件(WHERE name = ‘TXC’)等相关信息
  • 查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据:
SELECT id, name, since FROM product WHERE name = 'TXC';

得到前镜像数据如下:
image-5697f6dd
image-5697f6dd-1652350483233

  • 执行业务SQL:更新这条记录的name为’GTS’
  • 查询后镜像:根据前镜像的结果,通过主键定位数据
SELECT id, name, since FROM product WHERE id = '1';

得到后的镜像:
image-701bfcb3

  • 插入回滚日志:把前后镜像数据以及业务SQL相关的信息组成一条回滚日志记录。插到UNDO_LOG表中:
{
    "branchId": 641789253,
    "undoItems": [
        {
            "afterImage": {
                "rows": [
                    {
                        "fields": [
                            {
                                "name": "id",
                                "type": 4,
                                "value": 1
                            },
                            {
                                "name": "name",
                                "type": 12,
                                "value": "GTS"
                            },
                            {
                                "name": "since",
                                "type": 12,
                                "value": "2014"
                            }
                        ]
                    }
                ],
                "tableName": "product"
            },
            "beforeImage": {
                "rows": [
                    {
                        "fields": [
                            {
                                "name": "id",
                                "type": 4,
                                "value": 1
                            },
                            {
                                "name": "name",
                                "type": 12,
                                "value": "TXC"
                            },
                            {
                                "name": "since",
                                "type": 12,
                                "value": "2014"
                            }
                        ]
                    }
                ],
                "tableName": "product"
            },
            "sqlType": "UPDATE"
        }
    ],
    "xid": "xid:xxx"
}
  • 提交前,向TC注册分支:申请product表中,主键值等于1的记录的全局锁
  • 本地事务提交:业务数据的更新和前面步骤中生成的UNDO LOG一并提交
  • 将本地事务提交的结果报给TC
1.2.1.3.2 二阶段-回滚
  • 收到TC的分支回滚请求,开启一个本地事务。
  • 通过XID和Branch ID查找到相应的UNDO LOG记录
  • 数据校验:拿UNDO LOG中的后镜像与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的工作做了修改。这种情况下,需要根据配置策略来处理
  • 根据UNDO LOG中的前镜像和业务SQL的相关信息生成并执行回滚语句:
UPDATE product SET name = 'TXC' WHERE id = '1';
  • 提交本地事务,并把本地事务的执行结果上报给TC
1.2.1.3.3 二阶段-提交
  • 收到TC的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给TC
  • 异步任务阶段的分支提交请求将异步和批量地删除相应UNDO LOG记录

1.2.2 Seata TCC模式

一个分布式的全局事务,整体是两阶段提交的模型。全局事务是由若干分支事务组成的,分支事务要满足两阶段的提交要求,即需要每个分支事务都具备自己的:

  • 一阶段prepare行为
  • 二阶段commit或rollback行为

TCC与AT模式不同的是整个行为都是自定义的行为,且不依赖于底层数据资源的事务支持:

  • 一阶段prepare行为:调用自定义的prepare逻辑
  • 二阶段commit行为:调用自定义的commit逻辑
  • 二阶段rollback行为:调用自定义的rollback逻辑

TCC的方式注意使用幂等控制。

1.2.3 Seata Saga模式

Saga模式时Seata提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

目前Saga的实现是基于状态机引擎实现的。

1.2.3.1 基于状态机引擎的Saga实现

如下图所示:
image-9cfad813

  • 通过状态图来定义服务调用的流程并生成JSON状态语言定义文件
  • 状态图中一个节点可以调用一个服务,节点可以配置它的补偿节点
  • 状态图JSON由状态机引擎驱动执行,当出现异常时状态引擎反向执行已成功节点对应的补偿节点将事务回滚
  • 可以实现服务编排需求,支持单项选择、并发、子流程、参数转换、参数映射、服务执行状态判断、异常捕获等功能。

二 部署Server

2.1 部署Server集群

环境如下:

  • 两台CentOS7系统,IP分别是192.168.10.16和192.168.10.17。两台系统组成集群
  • Seata 1.1.0
  • MySQL5.7
  • JDK8
  • Nacos

Nacos的安装配置和使用我在这就不多做介绍了,具体可看:
Nacos + Spring Cloud

首先在两台服务器上安装JDK8,安装过程不做介绍

2.1.1 下载并安装

[root@CentOS7 ~]# wget https://github.com/seata/seata/releases/download/v1.1.0/seata-server-1.1.0.tar.gz
[root@CentOS7 ~]# tar xf seata-server-1.1.0.tar.gz -C /usr/src/
[root@CentOS7 ~]# cp /usr/src/seata/ /usr/local/seata -rf

2.1.2 修改注册中心

我这里使用Nacos作为配置中心和服务发现,file、apoll、redis、zk或consul等也可以举一反三。

修改/usr/local/seata/conf/registry.conf,将type改为nacos:

[root@CentOS7 ~]# vim /usr/local/seata/conf/registry.conf
registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    serverAddr = "192.168.10.3"
    namespace = ""
    cluster = "default"
  }
  ......
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "192.168.10.3"
    namespace = ""
    group = "SEATA_GROUP"
  }
  ......
}

其他内容不动或可删除。
注意,我这里使用的配置组是SEATA_GROUP

2.1.3 导入SQL

注意,在Seata1.1.0的压缩包中,没有配置和SQl脚本。需要去Seata的GitHub上下载。地址是:https://github.com/seata/seata/blob/1.1.0/script/server/db/mysql.sql

注意自己使用的版本,因为版本不同,配置和SQL有相应的变化,所以注意切换自己使用的版本。
1.1.0版本对应的SQL如下:

-- Server
-- 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;

创建数据库,然后将脚本导入到创建的库中(不做演示)。

2.1.4 导入配置

配置文件在压缩包中也没有包含,需要去Seata的GitHub上找,地址如下:
https://github.com/seata/seata/blob/1.1.0/script/config-center/config.txt

1.1.0版本的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.service_tx_group=default
service.default.grouplist=192.168.10.16:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
client.rm.asyncCommitBufferLimit=10000
client.rm.lockRetryInternal=10
client.rm.lockRetryTimes=30
client.rm.reportRetryCount=5
client.rm.lockRetryPolicyBranchRollbackOnConflict=true
client.rm.tableMetaCheckEnable=false
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
store.mode=db
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.jdbc.Driver
store.db.url=jdbc:mysql://192.168.10.3:3306/seata?useUnicode=true
store.db.user=root
store.db.password=123456
store.db.minConn=1
store.db.maxConn=3
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
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
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

这里注意几个地方:

  • service.vgroupMapping.service_tx_group=default:其中Key为service_tx_group,value为group,表示服务组映射。key和value都可以自定义。但是后面在客户端使用的时候,一定要配置与seata-server相同的key和value
  • store.mode=db:我这里使用数据库模式。如果使用file模式,则不支持集群
  • 还有就是数据库的配置,配置成自己的即可

具体的配置后面介绍

因为我们使用nacos作为配置中心,所以需要将配置导入到nacos中。可以使用脚本一键导入,也可以将上面的配置一个一个手动添加导入。如果使用手动导入,Data ID为key,Group为上述/usr/local/seata/conf/registry.conf配置的组,我这里是SEATA_GROUP。配置内容是value即可。

我这里使用脚本一键导入,脚本可以从Seata的GitHub上获取,地址是:
https://github.com/seata/seata/blob/1.1.0/script/config-center/nacos/nacos-config.sh

1.1.0版本的nacos-config.sh的内容如下:

#!/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:" opt
do
  case $opt in
  h)
    host=$OPTARG
    ;;
  p)
    port=$OPTARG
    ;;
  g)
    group=$OPTARG
    ;;
  t)
    tenant=$OPTARG
    ;;
  ?)
    echo "\033[31m USAGE OPTION: $0 [-h host] [-p port] [-g group] [-t tenant] \033[0m"
    exit 1
    ;;
  esac
done


if [[ -z ${host} ]]; then
    host=localhost
fi
if [[ -z ${port} ]]; then
    port=8848
fi
if [[ -z ${group} ]]; then
    group="SEATA_GROUP"
fi
if [[ -z ${tenant} ]]; then
    tenant=""
fi

nacosAddr=$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 "${1}" "http://$2/nacos/v1/cs/configs?dataId=$3&group=$group&content=$4&tenant=$tenant" >"${tempLog}" 2>/dev/null
  if [[ -z $(cat "${tempLog}") ]]; then
    echo "\033[31m Please check the cluster status. \033[0m"
    exit 1
  fi
  if [[ $(cat "${tempLog}") =~ "true" ]]; then
    echo "Set $3=$4\033[32m successfully \033[0m"
  else
    echo "Set $3=$4\033[31m failure \033[0m"
    (( failCount++ ))
  fi
}

count=0
for line in $(cat $(dirname "$PWD")/config.txt); do
  (( count++ ))
    key=${line%%=*}
  value=${line#*=}
    addConfig "${contentType}" "${nacosAddr}" "${key}" "${value}"
done

echo "========================================================================="
echo " Complete initialization parameters, \033[32m total-count:$count \033[0m, \033[31m failure-count:$failCount \033[0m"
echo "========================================================================="

if [[ ${failCount} -eq 0 ]]; then
    echo "\033[32m Init nacos config finished, please start seata-server. \033[0m"
else
    echo "\033[31m init nacos config fail. \033[0m"
fi

注意:

  • 不要直接将文件放到Linux服务器上,因为字符集的原因会无法解析,而是使用vim创建nacos-config.sh,然后将内容复制进去
  • nacos-config.sh和config.txt文件需要注意路径。config.txt需要放在nacos-config.sh所在目录的上一层目录。也可以更改上述的脚本(我这里就不改上述的脚本了)。比如nacos-config.sh在/root/script目录下,那么config.txt就需要在/root目录下

最后运行nacos-config.sh脚本:

[root@seata1 ~]# bash -x nacos-config.sh -h 192.168.10.3 -p 8848 -g SEATA_GROUP
  • -h:Nacos地址
  • -p:Nacos端口号。默认为8848
  • -g:使用的服务组。与上述的配置文件/usr/local/seata/conf/registry.conf中配置保持一致
  • -t:Nacos的namespace。默认为空

最后在Nacos中看到配置如下即表示配置成功:
image-b754f94f

2.1.5 启动

最后就可以启动服务了。可以根据需求自行修改日志文件的路径(修改/usr/local/seata/conf/logback.xml即可)。

制作systemd脚本:

[root@seata1 ~]# vim /usr/lib/systemd/system/seata-server.service
[Unit]
Description=Seata Server
After=network.target

[Service]
ExecStart=/usr/local/seata/bin/seata-server.sh -h 192.168.10.16 -p 8091 -m db -n 1
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
  • -h:表示Seata监听的地址。0.0.0.0表示全部
  • -p:表示监听的端口号。默认为8091
  • -m:使用的模式,为db
  • -n:节点唯一表示。如果是多个节点,则需要配置为不同的ID。

其中192.168.10.17的配置过程与上述类似。省去导入SQL数据和导入配置的过程,而是解压 --> 配置/usr/local/seata/conf/registry.conf --> 启动

写好脚本后,使用如下命令启动:

[root@seata1 ~]# systemctl daemon-reload
# 启动
[root@seata1 ~]# systemctl start seata-server
# 停止
[root@seata1 ~]# systemctl stop seata-server
# 重启
[root@seata1 ~]# systemctl restart seata-server
# 查看状态
[root@seata1 ~]# systemctl status seata-server

最后在注册中心服务列表中看见如下,表示集群配置成功:
image-931f720b

2.2 配置介绍

2.2.1 公共部分

配置项 描述 备注
transport.serialization Client和Server通信编码方式 seata、protobuf、kryo、hession。默认为seata
transport.compressor Client和Server通信数据压缩方式 none、gzip。默认为none
transport.heartbeat Client和Server通信心跳检测开关 默认为true开启
registry.type 注册中心类型 默认为file。支持file、nacos、eureka、redis、zk、consul、etcd3、sofa、custom
config.type 配置中心类型 默认为file。支持file、nacos、epollo、zk、consul、etcd3、custom

2.2.2 Server端

配置项 描述 备注
server.undo.log.save.days undo日志保留天数 默认为7天。log_status=1(如下注释)和未正常清理的undo。
server.undo.log.delete.period undo清理线程间隔时间 默认86400000,单位为毫秒
server.max.commit.retry.timeout 二阶段提交重试超时时长 单位ms、s、m、h、d,分别对应毫秒、秒、分、时、天,默认为毫秒。默认值为-1,表示无限重试
server.max.rollback.retry.timeout 二阶段回滚重试超时时长 同commit
server.recovery.committing-retry-period 二阶段提交未完成状态全局事务重试提交线程间隔时间 默认1000, 单位毫秒
server.recovery.asyn-committing-retry-period 二阶段异步提交状态重试提交线程间隔时长 默认1000, 单位毫秒
server.recovery.rollbacking-retry-period 二阶段回滚状态重试回滚线程间隔时间 默认1000, 单位毫秒
server.recovery.timeout-retry-period 超时状态监测重试线程间隔时间 默认1000, 单位毫秒,检测出超时将全局事务置入回滚会话管理器
store.mode 事务会话信息存储方式 file本地文件。这种方式不支持集群模式,db数据库模式支持集群
store.file.dir file模式文件存储文件夹名 默认sessionStore
store.db.datasource db模式数据源类型 默认dbcp
store.db.db-type db模式数据库类型 默认MySQL
store.db.driver-class-name db模式数据驱动 默认com.mysql.jdbc.Driver
store.db.url db模式数据库url 默认jdbc:mysql://127.0.0.1:3306/seata
store.db.user db模式数据库用户名 默认mysql
store.db.password db模式数据库密码 默认mysql
store.db.min-conn db模式数据库初始连接数 默认1
store.db.max-conn db模式数据库最大连接数 默认3
store.db.global.table db模式全局事务表名 默认global_table
store.db.branch.table db模式分支事务表名 默认branch_table
store.db.lock-table db模式全局锁表名 默认lock_table
store.db.query-limit db模式查询全局事务一次的最大条数 默认100
metrics.enabled 是否启用Metrics 默认false关闭,在false下,所有Metrics相关的组件将不会被初始化,使得性能损耗降到最低
metrics.registry-type 指标注册器类型 Metrics使用的指标注册器类型,默认为内置的compact(简易)实现,这个实现中的Meter仅使用有限内存计数,性能高足够满足大多数场景;目前只能设置一个指标注册器实现
metrics.exporter-list 指标结果数据输出器列表 默认prometheus,多个输出器使用英文逗号分割,例如"prometheus,jmx",目前仅实现了对接prometheus的输出器
metrics.exporter-prometheus-port premetheus输出器Client端口号 默认9898

其中log_status=1是防御性的。是收到全局回滚请求,但是不确定某个事务分支的本地事务是否已经执行完成了,这时事先插入一条branchid相同的数据,插入的假数据成功了。本地事务继续执行就会报主键冲突自动回滚。加入插入不成功说明表里有数据这个本地事务已经执行完成了,那么取出这条undo log数据做反向回滚操作

2.2.3 Client端

配置项 描述 备注
seata.enable 是否开启Spring Boot自动装配 默认为true。(具体请看下面解释)
client.report.success.enable 是否上报一阶段成功 默认为true用于保持分支事务声明周期记录的完整,false可提高不少性能
transport.enable-client-batch-send-request 客户端事务消息请求是否批量合并发送 默认为true,false单条发送
client.log.exception-rate 日志异常输出概率 默认100,目前用于undo回滚失败时异常堆栈输出,百分之一的概率输出,回滚失败基本是脏数据,无需输出堆栈占用硬盘空间
service.vgroup_mapping.service_tx_group 事务群组(具体请看下面解释) service_tx_group为分组,配置项为TC集群名。与上面的seata-server配置保持一致
service.default.grouplist TC服务列表(具体请看下面解释) 仅注册中心为file时使用
service.disable-global-transaction 全局事务是否禁用 默认为false
service.enable-degrade 降级开关 默认false。业务侧根据连续错误数自动降级不走seata
client.rm.async.commit.buffer.limit 异常提交缓存队列长度 默认10000,二阶段提交成功,RM清理undo队列
client.rm.lock.retry.internal 校验或占用全局锁重试间隔 默认为10,单位毫秒
client.rm.retry.times 校验或占用全局锁重试次数 默认30
client.rm.lock.retry.policy.branch-rollback-on-conflict 分支事务与其他全局回滚事务冲突时锁策略 默认true,优先释放本地锁让回滚成功
client.rm.report.retry.count 一阶段结果上报TC重试次数 默认5次
client.rm.table.meta.check.enable 自动刷新缓存中的表结构 默认false
client.tm.commit.retry.count 一阶段全局提交结果上报TC重试次数 默认1次,建议大于1次
client.tm.rollback.retry.count 一阶段全局回滚结果上报TC重试次数 默认1次,建议大于1次
client.undo.data.validation 二阶段回滚镜像校验 默认true开启
client.undo.log.serialization undo序列化方式 默认jackson
client.undo.log.table 自定义undo表名 默认undo_log
client.support.spring.datasource.autoproxy 数据源自动代理开关 默认false关闭
  • 事务群组(service.vgroup_mapping.service_tx_group):事务分组是Seata的资源逻辑,类似于服务实例。在seata-server的配置中service_tx_group就是一个分组。通过事务分组,首先程序中配置了事务分组(GlobalTransactionScanner构造方法的txServiceGroup参数),程序会通过用户配置的配置中心去找service.vgroup_mapping.事务分组配置项,去的配置项的值就是TC集群的名称。拿到集群名称程序通过一定的前缀+集群名称去构造服务名,拿到服务名去相应的注册中心拉取相应服务名的服务列表,获得后端真实的TC服务列表。
  • TC服务列表:当regitry.type=file时会用到,其他时候不需配置。可以配置多个。但当store.mode=file时,会报错。原因是在file存储模式下未提供本地文件的同步,所以需要store.mode=db,通过DB来共享TC集群间数据。不推荐使用,因为当registry.type=file时会用到,即这里使用的不是真正的注册中心
  • 是否开启Spring Boot自动装配:如果开启,需要使用Spring Boot版本。包括数据源的自动代理以及GlobalTransactionScanner初始化。
0

评论区