程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • 微服务基础

    • 了解SpringCloud微服务架构
    • 启动多个微服务项目
    • Eureka 服务注册
    • Ribbon 负载均衡
    • Nacos 下载与安装
    • Nacos 服务注册
    • Nacos 配置管理
    • openFeign 远程调用
    • OpenFeign 最佳实践
    • Gateway 网关
    • Gateway 进阶使用
    • Sentinel 服务保护
    • Sentinel 整合 Feign
    • 分布式事务 Seata
      • 1、简介
      • 2、Seata简介
      • 3、安装
      • 4、XA规范
      • 5、AT模式
      • 6、TCC模式
      • 7、SAGA模式
    • 什么是分布式
    • 什么是RPC框架
  • 微服务之DDD架构思想

  • 微服务
  • 微服务基础
scholar
2024-03-23
目录

分布式事务 Seata

# 1、简介

  1. 事务基本要求:ACID,原子性、一致性、隔离性、持久性。

  2. 本章解决问题:

    基于微服务的分布式事务。在分布式系统下,一个业务跨越多个服务或数据源,每个服务都是一个分支事务,要保证所有分支事务最终状态一致,这样的事务就是分布式事务。

  3. CAP定理

    1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有 3 个指标:

    • Consistency:一致性
    • Available:可用性
    • Partition tolerance:分区容错性

    于是 CAP 定理的内容为:

    • 分布式系统节点通过网络连接,一定会出现分区问题(P)
    • 当分区出现时,系统的一致性(C)和可用性(A)就无法同时满足

    我们之前搭建的 Elasticsearch 集群属于 CP,不属于 AP。

  4. BASE理论

    解决CAP存在的问题

    • Basically Available(基本可用):在分布式系统出现故障时,允许损失部分可用性,但保证核心可用。
    • Soft State(软状态):在规定时间内允许出现不一致状态。
    • Eventually Consistent(最终一致性):数据最终会达到一致性。

    解决的方式:

    • 【AP模式】:各子事务分别提交,允许出现结果的不一致,然后采用措施恢复数据,最终达到一致性。
    • 【CP模式】:各子事务执行后互相等待,同时提交、同时回滚,最终达到一致性。但在事务等待的过程,本次服务处于弱可用,同时因为各子事务必须彼此感知各自事务状态才能保证一致性,因此需要一个“事务协调者”负责协调,由此也诞生出了全局事务、分支事务的概念。

    image-20230103095127280

# 2、Seata简介

分布式事务解决方案,http://seata.io/zh-cn/

每个微服务都需配置 Seata,略微繁琐

  1. 简介:
    • Seata 是 2019 年 1 月份蚂蚁金服与阿里巴巴共同开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。
    • Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

image-20230103100757117

  1. Seata 事务中有 3 个重要角色

    • TC(Transaction Coordinator)事务协调者:维护全局事务和分支事务的状态,协调全局事务的提交与回滚。
    • TM(Transaction Manager)事务管理器:定义全局事务的范围,开启、提交或回滚全局事务。
    • RM(Resource Manager)资源管理器:管理分支事务,向 TC 注册分支事务并报告状态,提供分支事务的提交与回滚功能。

    Seata 就是 TC(作为TC,搭建成功后我们不需要访问它,这是给 TM 和 RM 访问的),企业中需要搭建集群。

    image-20230103100039651

  2. Seata提供了 4 种不同的分布式事务处理方案:

    • XA模式:强一致性分布阶段事务模式,牺牲一定可用性,无业务侵入。
    • AT模式(默认):最终一致的分阶段事务模式,无业务侵入。
    • TCC模式:最终一致的分阶段事务模式,有业务侵入。
    • SAGA模式:长事务模式,有业务侵入。

    image-20230104110821379

# 3、安装

1. 下载 seata-server 包并解压:https://github.com/seata/seata/releases

image-20230103125550806

2. 修改conf目录下的application.yml文件

1.4.2版本为registry.conf

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata
  # 若无以下配置则注释
  # extend:
  #   logstash-appender:
  #     destination: 127.0.0.1:4560
  #   kafka-appender:
  #     bootstrap-servers: 127.0.0.1:9092
  #     topic: logback_to_logstash

console:
  user:
    username: seata
    password: seata

seata:
	# 配置中心
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: ""		# 命名空间为空,默认 public
      group: SEATA_GROUP
      username: nacos
      password: nacos
      data-id: seataServer.properties
  # 注册中心
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: ""
      group: DEFAULT_GROUP
      username: nacos
      password: nacos
      cluster: SH 	# SH表示上海
  # 已经配置了 nacos 作为配置中心,所以这里 store 与 server 不配置
  # store:
    # support: file 、 db 、 redis
    # mode: file
#  server:
#    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login
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

3. 新建数据库 seata,在此基础上新增两张表branch_table与global_table作事务管理。

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS `branch_table`;
CREATE TABLE `branch_table`  (
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `transaction_id` bigint(20) NULL DEFAULT NULL,
  `resource_group_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `branch_type` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `status` tinyint(4) NULL DEFAULT NULL,
  `client_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `gmt_create` datetime(6) NULL DEFAULT NULL,
  `gmt_modified` datetime(6) NULL DEFAULT NULL,
  PRIMARY KEY (`branch_id`) USING BTREE,
  INDEX `idx_xid`(`xid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;


DROP TABLE IF EXISTS `global_table`;
CREATE TABLE `global_table`  (
  `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `transaction_id` bigint(20) NULL DEFAULT NULL,
  `status` tinyint(4) NOT NULL,
  `application_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `transaction_service_group` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `transaction_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `timeout` int(11) NULL DEFAULT NULL,
  `begin_time` bigint(20) NULL DEFAULT NULL,
  `application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `gmt_create` datetime NULL DEFAULT NULL,
  `gmt_modified` datetime NULL DEFAULT NULL,
  PRIMARY KEY (`xid`) USING BTREE,
  INDEX `idx_gmt_modified_status`(`gmt_modified`, `status`) USING BTREE,
  INDEX `idx_transaction_id`(`transaction_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 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

4. Nacos 新建配置文件

为 Seata 集群作准备

Nacos创建seataServer.properties配置文件,修改 MySQL 数据库信息,其余配置默认。

image-20230103153636718

# 数据存储方式,db代表数据库
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.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
# 事务、日志等配置
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.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000

# 客户端与服务端传输方式
transport.serialization=seata
transport.compressor=none
# 关闭metrics功能,提高性能
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
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

5. 启动:

Linux 选择.sh,Windows 选择.bat。

另外注意这里可能会报nohup: /Library/Internet: No such file or directory错误,原因是JDK路径查找失败;

./bin/seata-server.sh
1

6. 查看启动日志: /seata/logs/start.out判断是否启动成功。

7. 微服务中引入依赖并配置连接

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
		<!-- 排除旧版本 Seata ,引入 1.6.1 版本 -->  
    <exclusions>
        <exclusion>
            <artifactId>seata-spring-boot-starter</artifactId>
            <groupId>io.seata</groupId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.6.1</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

nacos服务名称必须包括 4 部分,而且每个微服务都必须配置这些信息,微服务将根据这些信息去注册 Seata。

  • namespace
  • group
  • serviceName
  • cluster
seata:
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: ""
      group: DEFAULT_GROUP
      application: seata-server		# TC 在 Nacos 中的名称
      tx-service-group: seata-demo
      service:
        vgroup-mapping:
          seata-demo: SH
1
2
3
4
5
6
7
8
9
10
11
12

image-20230103154337068

  1. 重启微服务,查看 Seata 日志

image-20230103191850421

# 4、XA规范

image-20230103215608119

  1. 分阶段事务模式,几乎所有的主流数据库都对其提供了支持。

  2. 示意图:

    image-20230103193706690

  3. 优点:

    • 事务具有强一致性,满足ACID
    • 常用数据库均支持,实现简单、无代码侵入
  4. 缺点:

    • 事务之间耦合度很高
    • 事务之间相互等待,性能较差
    • 事务的实现依赖于关系型数据库
  5. 实现步骤

    • 各微服务附加配置后重启
    • 业务 Service 加 全局事务注解 @GlobalTransaction
    seata:
    	data-source-proxy-mode: XA		# 使用 XA 模式
    
    1
    2
    @Override
    @GlobalTransactional
    public void create(Order order) {
        // 创建订单
        // 扣用户余额
        // 扣库存
    }
    
    1
    2
    3
    4
    5
    6
    7
  6. 【补充说明】data-source-proxy-mode配置的作用:

    设置数据源代理模式,Seata 通过劫持数据源data-source来实现分布式事务的管理,配置后所有事务都将由 Seata 托管。

# 5、AT模式

默认

image-20230103215608119

  1. 同样是分阶段事务模式,弥补了 XA 模式中资源锁定周期过长的缺陷,但同时也牺牲了一些安全性。

  2. 示意图:允许先成功,后续使用 undo log 进行回滚。

    image-20230103215921725

  3. 【脏读问题】:

    这里阐述比较复杂,总之 AT 模式就是牺牲一定的安全性换来效率

  • 由于各事务在一定程度上存在“独立性”,所以 AT 模式存在“脏读”现象。

  • AT 模式新增**【全局锁】**用来防止数据脏读,当数据遇到同时 update 请求时,全局锁会限制另一方的提交,直到原来的一方释放全局锁,此时 AT 模式相当于退化为 XA 模式。

  • 但是全局锁只能作用于 Seata 事务,也就是说对非 Seata 管理的事务无效,在这种情况下依旧会产生“脏读”现象(无法解决)。幸运的是,Seata 能察觉这种现象的产生并抛出异常,我们可以捕获这种异常并编写代码发送邮件告知服务管理者。

  • 当数据没有发生“脏读”问题时,AT模式效率较高,原因如下:

    • 事务分布式提交,突破“木桶效应”限制。

      • Seata 的“全局锁”粒度较细,只锁字段中的具体数据,对相同字段的其他数据无影响。
      • MySQL 属于“粗粒度”锁,会锁住整张表,极大的降低效率。
      // 例如在下面字段中,当 name 被某事务支配时,money字段并不受影响
      {"id":1,"name":"张三","money":100}
      
      1
      2

image-20230103224221821

  1. 【 XA模式 与 AT模式 总结】

    AT模式牺牲的只是一些比较小的安全性(sava 与 update 属于“小概率”操作),换来的是极大的效率提升,在业务sava 与 update 次数较少且安全性要求不高的数据库,应优先使用AT模式。

  2. 实现步骤

    • 数据库新建 2 张表,存储在不一样地方
      • lock_table:导入到与 TC(即 Seata 服务端)相关联的数据库
      • undo_log:导入到与微服务相关的数据库(也就是在每个相关的微服务数据库中都需要导入undo_log表)
    • 修改相关微服务的application.yml配置文件,声明为使用 AT 模式(其实默认模式)。
    DROP TABLE IF EXISTS `lock_table`;
    CREATE TABLE `lock_table`  (
      `row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
      `xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `transaction_id` bigint(20) NULL DEFAULT NULL,
      `branch_id` bigint(20) NOT NULL,
      `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `pk` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `gmt_create` datetime NULL DEFAULT NULL,
      `gmt_modified` datetime NULL DEFAULT NULL,
      PRIMARY KEY (`row_key`) USING BTREE,
      INDEX `idx_branch_id`(`branch_id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    DROP TABLE IF EXISTS `undo_log`;
    CREATE TABLE `undo_log`  (
      `branch_id` bigint(20) NOT NULL COMMENT 'branch transaction id',
      `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'global transaction id',
      `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci 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 INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'AT transaction mode undo table' ROW_FORMAT = Compact;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    seata:
    	data-source-proxy-mode: AT
    12
    
    1
    2
    3

# 6、TCC模式

image-20230103215608119

TCC模式效率很高,但过于复杂

具体案例见:链接 (opens new window)

  1. 简介

    需编写代码分别实现 3 个阶段

    • Try:资源检查和预留
    • Confirm:业务执行和提交
    • Cancel:预留资源释放
  2. 示意图:

    image-20230104092446185

  3. 优点:

    • 分布式提交事务,效率高
    • 相比 AT 模式,无需生成快照(即 undo_log)、无需使用全局锁,性能最强
    • 依赖补偿操作,不依赖数据库事务,可用于非事务型数据库
  4. 缺点:

    • 代码侵入性很强,需同时编写 try、confirm、cancel 接口,特别繁琐与麻烦
    • 事务最终一致而不是强一致
    • 需要考虑Confirm与Cancel失败的情况,即做好幂等处理
    • 另外需要注意空回滚的情况
  5. 【名词解释】

    • 空回滚:当某分支事务的 try 阶段阻塞时,可能导致全局事务超时而触发其他服务的 cancel 操作。在未执行 try 操作时先执行了 cancel 操作,这时 cancel 不能做回滚,就是空回滚。
    • 幂等处理:对于已经空回滚的业务,如果以后继续执行 try,就永远不可能 confirm 或 cancel ,这就是业务悬挂(应当阻止执行空回滚后的 try 操作,避免悬挂)。
  6. 举例

    image-20230104104318338

    image-20230104110106289

# 7、SAGA模式

image-20230103215608119

TCC模式的“简化版”,牺牲了一定的安全性,存在数据“脏读”风险

Saga模式在实际中很少被运用

  1. 简介:

    Saga模式是 Seata 提供的长事务解决方案,具体分为两个阶段:

    • 一阶段:直接提交本地事务
    • 二阶段:成功则什么也不做,失败则通过编写补偿业务回滚
  2. 优点:

    • 类似 TCC,但不用编写 TCC 中 3 个阶段,实现简单
    • 事务参与者可以基于事件驱动实现异步调用,吞吐量高
    • 无锁,一阶段直接提交事务,性能好
  3. 缺点:

    • 没有锁与事务隔离性,存在数据“脏写”情况
    • 软状态持续的时间不确定,时效性较差
编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08
Sentinel 整合 Feign
什么是分布式

← Sentinel 整合 Feign 什么是分布式→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式