微服务事务
CYY

什么是微服务事务

在某个微服务业务中,业务需要对数据库进行多次操作,其中对数据库的操作又由其他微服务业务完成,这整个业务所涉及的数据库操作需要同时成功或者同时失败。

微服务事务和单体架构的事务有何区别

在传统微服务业务中,对数据库的操作都包含在同一个数据库,可以依靠数据库自带的事务进行管理。在微服务中,每一个微服务都会对应自己的数据库,因此业务对数据库的操作涉及多个微服务业务对其自己的数据库进行操作。这时无法依靠数据库自带的事务进行处理。

微服务事务的处理架构

seata 架构

三个角色和两种模式

TM(Transaction Manager):事务管理,通知 TC 开启与结束一个事务,或者回滚事务

RM(Resource Manager):分支事务管理,主要功能是注册子事务,报告子事务状态(成功/失败),接收 TC 的命令执行提交或回滚。

TC(Transaction Coordinator):事务协调器,独立的微服务,维护事务的运行状态
根据 TM 的指示开启事务记录以及事务完成后检查事务涉及的分支事务是否全部成功完成,若全部成功完成执行提交,若未成功完成执行回滚。

例子

如下图的订单业务,订单业务中需要生成订单,清除购物车,扣除库存。生成订单的操作和订单业务同属一个微服务,操作的同一个数据库。但是清除购物车的操作属于购物车微服务,操作的数据库和生成订单业务操作的数据库不同。扣除库存操作同理。

AT 模式

在 AT 工作模式下,订单业务开始时,TM 会通知 TC 开启一个事务,随后依次执行生产订单,清除购物车,扣除库存子业务。当执行生成订单操作时,RM 会向 TC 发起注册通知,表面子业务开始执行,当执行完后立即提交此子业务的事务,然后生成undo log(非 mysql 的 undo log),再通知 TC 子业务执行完成。其他子业务同理。

最后订单业务执行完成后,TM 通知 TC 业务执行完毕,TC 这时检查每个分支事务执行情况,若有一个执行失败则发通知给 RM,令其根据 undo log 进行回滚。若均执行成功则会删除 undo log

AT 模式的优点是性能高,其缺点是一致性差,由于分支事务完成后立即提交,若后续的分支事务出现错误,在这个过程中其他业务所得到的数据结果是脏数据,只有等回滚后数据才是正确的,因此AT 模式只能保证结果一致性。

XA 模式

XA 模式和 AT模式的主要区别在于,其子业务执行后不会立即提交,因此也不会生成 undo log(非 mysql 的 undo log),等整个业务完成后,依靠 TC 的通知决定回滚还是统一提交。

所以其优点是数据一致性高,但其缺点也很明显,它的性能低。

Seata 在 SpringBoot 中的集成

部署 TC

  1. 准备数据库表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
CREATE DATABASE IF NOT EXISTS `seata`;
USE `seata`;


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;


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;


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);
  1. 准备配置文件

点此下载配置文件

下载文件后,修改配置文件中的 mysql 连接信息和 nacos 信息,然后将整个文件夹上传到服务器的 home 目录。
  1. Docker 部署
1
2
3
4
5
6
7
8
9
docker run --name seata \
-p 8099:8099 \
-p 7099:7099 \
-e SEATA_IP=192.168.192.101 \
-v ./seata:/seata-server/resources \
--privileged=true \
--ulimit nofile=65536:65536 \
-d \
seataio/seata-server:1.5.2

微服务中集成 RM

  1. 导入依赖
1
2
3
4
5
<!--seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
  1. 编写配置

    在 nacos 中添加共享的配置 shared-seata.yaml,随后在各微服务配置拉取此配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
seata:
registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址
type: nacos # 注册中心类型 nacos
nacos:
server-addr: 192.168.150.101:8848 # nacos地址
namespace: "" # namespace,默认为空
group: DEFAULT_GROUP # 分组,默认是DEFAULT_GROUP
application: seata-server # seata服务名称
username: nacos
password: nacos
tx-service-group: hmall # 事务组名称
service:
vgroup-mapping: # 事务组与tc集群的映射关系
hmall: "default"
# data-source-proxy-mode: XA
# 默认为 AT模式
  1. 使用 AT 模式必须要添加数据库表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS
`undo_log`
(
`branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
`context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
`log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';

微服务中集成 TM

使用 @GlobalTransactional 标注事务即可集成 TM

 Comments
Comment plugin failed to load
Loading comment plugin
Powered by Hexo & Theme Keep