上篇讲述gateway的部署和使用,gateway统一管理和转发了HTTP请求,在互联网中大型项目一定存在复杂的业务关系,尤其在商城类软件中如淘宝、PDD等商城,尤其在秒杀场景中,并发量可以到达千万级别,此时数据库就会显得很无力。
以Mysql为例,熟悉数据库的童鞋都知道数据库有原子性、隔离性、一致性、持久性四大特性,隔离级别分为脏读、幻读、可重复读、序列化四种。Mysql默认的隔离级别在可重复读,在高并发中显然会出现大量可重复度数据,分布式数据库显然是最适合的解决方案 。
1、Seata介绍
Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
模式 | |
TC - 事务协调者 | 维护全局和分支事务的状态,驱动全局事务提交或回滚。 |
TM - 事务管理器 | RM (Resource Manager) - 资源管理器 |
RM - 资源管理器 | 管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。 |
2、Seata服务部署
seata数据库脚本:https://github.com/seata/seata/blob/1.5.2/script/server/db/mysql.sql
seata配置文件:https://github.com/seata/seata/blob/1.5.2/script/config-center/config.txt
下载seata的压缩包,并且解压,在seata/script/server/db/下找到sql脚本
在mysql中创建名为seata的数据库,并执行脚本:
-
-- -------------------------------- 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
= utf
8mb
4;
-
-
-- 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
= utf
8mb
4;
-
-
-- 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
= utf
8mb
4;
-
-
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
= utf
8mb
4;
-
-
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);
在seata/script/config-center/下找到config.txt 配置文件。
seata需要集成到微服务中去,所以配置文件我们依然使用nacos管理。
-
#
For details about
configuration items, see https:
/
/seata.io
/zh-cn
/docs
/user
/configurations.html
-
#Transport
configuration,
for client
and server
-
transport.
type
=TCP
-
transport.server
=NIO
-
transport.heartbeat
=
true
-
transport.enableTmClientBatchSendRequest
=
false
-
transport.enableRmClientBatchSendRequest
=
true
-
transport.enableTcServerBatchSendResponse
=
false
-
transport.rpcRmRequestTimeout
=
30000
-
transport.rpcTmRequestTimeout
=
30000
-
transport.rpcTcRequestTimeout
=
30000
-
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
-
transport.serialization
=seata
-
transport.compressor
=none
-
-
#Transaction routing rules
configuration, only
for the client
-
service.vgroupMapping.
default_tx_
group
=
default
-
#
If you
use a registry, you can ignore it
-
service.
default.grouplist
=
127.0.0.1:
8091
-
service.enableDegrade
=
false
-
service.disableGlobalTransaction
=
false
-
-
#Transaction rule
configuration, only
for the client
-
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
=
true
-
client.rm.tableMetaCheckerInterval
=
60000
-
client.rm.sqlParserType
=druid
-
client.rm.reportSuccessEnable
=
false
-
client.rm.sagaBranchRegisterEnable
=
false
-
client.rm.sagaJsonParser
=fastjson
-
client.rm.tccActionInterceptorOrder
=-
2147482648
-
client.tm.commitRetryCount
=
5
-
client.tm.rollbackRetryCount
=
5
-
client.tm.defaultGlobalTransactionTimeout
=
60000
-
client.tm.degradeCheck
=
false
-
client.tm.degradeCheckAllowTimes
=
10
-
client.tm.degradeCheckPeriod
=
2000
-
client.tm.interceptorOrder
=-
2147482648
-
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
-
#
For TCC transaction
mode
-
tcc.fence.logTableName
=tcc_fence_log
-
tcc.fence.cleanPeriod
=
1h
-
-
#Log rule
configuration,
for client
and server
-
log.exceptionRate
=
100
-
-
#Transaction storage
configuration, only
for the server. The
file, DB,
and redis
configuration
values
are
optional.
-
store.
mode
=
file
-
store.
lock.
mode
=
file
-
store.session.
mode
=
file
-
#Used
for password encryption
-
store.publicKey
=
-
-
#
If `store.
mode,store.
lock.
mode,store.session.
mode`
are
not
equal
to `
file`, you can remove the
configuration
block.
-
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
-
-
#These configurations
are required
if the `store
mode`
is `db`.
If `store.
mode,store.
lock.
mode,store.session.
mode`
are
not
equal
to `db`, you can remove the
configuration
block.
-
store.db.datasource
=druid
-
store.db.dbType
=mysql
-
store.db.driverClassName
=com.mysql.jdbc.Driver
-
store.db.url
=jdbc:mysql:
/
/
127.0.0.1:
3306
/seata?useUnicode
=
true
&rewriteBatchedStatements
=
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.distributedLockTable
=distributed_
lock
-
store.db.queryLimit
=
100
-
store.db.lockTable
=
lock_
table
-
store.db.maxWait
=
5000
-
-
#These configurations
are required
if the `store
mode`
is `redis`.
If `store.
mode,store.
lock.
mode,store.session.
mode`
are
not
equal
to `redis`, you can remove the
configuration
block.
-
store.redis.
mode
=single
-
store.redis.single.host
=
127.0.0.1
-
store.redis.single.port
=
6379
-
store.redis.sentinel.masterName
=
-
store.redis.sentinel.sentinelHosts
=
-
store.redis.maxConn
=
10
-
store.redis.minConn
=
1
-
store.redis.maxTotal
=
100
-
store.redis.database
=
0
-
store.redis.password
=
-
store.redis.queryLimit
=
100
-
-
#Transaction rule
configuration, only
for the server
-
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
-
server.distributedLockExpireTime
=
10000
-
server.xaerNotaRetryTimeout
=
60000
-
server.session.branchAsyncQueueSize
=
5000
-
server.session.enableBranchAsyncRemove
=
false
-
server.enableParallelRequestHandle
=
false
-
-
#Metrics
configuration, only
for the server
-
metrics.enabled
=
false
-
metrics.registryType
=compact
-
metrics.exporterList
=prometheus
-
metrics.exporterPrometheusPort
=
9898
将上面seata的t配置文件config.tx导入到nacos:
修改seata的配置文件内容 :
-
# 修改store.
mode为db,配置数据库连接
-
store.
mode
=db
-
store.db.dbType
=mysql
-
store.db.driverClassName
=com.mysql.cj.jdbc.Driver
-
store.db.url
=jdbc:mysql:
/
/localhost:
3306
/seata?useUnicode
=
true
&rewriteBatchedStatements
=
true
-
store.db.user
=数据库用户名
-
store.db.password
=数据库密码
在seata/config/application.yml 修改seata配置信息:
-
seata:
-
config:
-
type: nacos
-
nacos:
-
server-addr: 127.0.0.1:8848
-
namespace:
-
group: SEATA_GROUP
-
data-id: seataServer.properties
-
registry:
-
type: nacos
-
preferred-networks: 30.240.*
-
nacos:
-
application: seata-server
-
server-addr: 127.0.0.1:8848
-
namespace:
-
group: SEATA_GROUP
-
cluster: default
-
#store:
-
#mode: file
最后到seata/bin目录下运行seata-server.bat即可启动seata服务。在nacos服务列表里可以看到seata已经被注册到nacos中:
3、项目集成
在父级工程下创建seata子级工,添加seata依赖:
-
<dependency>
-
<groupId>com.alibaba.cloud
</groupId>
-
<artifactId>spring-cloud-starter-alibaba-seata
</artifactId>
-
<exclusions>
-
<exclusion>
-
<groupId>io.seata
</groupId>
-
<artifactId>seata-spring-boot-starter
</artifactId>
-
</exclusion>
-
</exclusions>
-
</dependency>
-
<dependency>
-
<groupId>io.seata
</groupId>
-
<artifactId>seata-spring-boot-starter
</artifactId>
-
<version>1.5.2
</version>
-
</dependency>
在需要使用全局事务管理的服务中添加seata子级工程依赖,在处理数据库业务的时候添加@GlobalTransactional注解代替@Transactional注解就可以了。
转载:https://blog.csdn.net/liukangjie520/article/details/129092848