dubbo调用超时回滚_微服务痛点基于Dubbo + Seata的分布式事务(AT模式)

本文详细介绍了Seata的AT模式,解释了AT模式的原理及无侵入特性。并通过一个Dubbo + Seata的实战案例,展示了如何在存储、订单和业务模块中接入分布式事务,包括正常流程和异常处理,帮助读者理解AT模式在实际应用中的工作流程。
摘要由CSDN通过智能技术生成
eee3429759044e7d9e7ae60dd56d1653.png

前言

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。对于Seata不太了解的朋友,可以看下我之前写的文章: 微服务开发的最大痛点-分布式事务SEATA入门简介。

AT模式

AT模式怎么理解

AT模式下,每个数据库被当做是一个Resource,Seata 里称为 DataSource Resource。业务通过 JDBC 标准接口访问数据库资源时,Seata 框架会对所有请求进行拦截,做一些操作。

每个本地事务提交时,Seata RM(Resource Manager,资源管理器) 都会向 TC(Transaction Coordinator,事务协调器) 注册一个分支事务。当请求链路调用完成后,发起方通知 TC 提交或回滚分布式事务,进入二阶段调用流程。此时,TC 会根据之前注册的分支事务回调到对应参与者去执行对应资源的第二阶段。

TC 是怎么找到分支事务与资源的对应关系呢?每个资源都有一个全局唯一的资源 ID,并且在初始化时用该 ID 向 TC 注册资源。在运行时,每个分支事务的注册都会带上其资源 ID。这样 TC 就能在二阶段调用时正确找到对应的资源。这就是我们的 AT 模式。简单总结一下,就是把每个数据库当做一个 Resource,在本地事务提交时会去注册一个分支事务。

AT模式是一种无侵入的分布式事务解决方案。在AT模式下,用户只需关注自己的"业务SQL",用户的"业务SQL"作为第一阶段,Seata框架会自动生成事务的二阶段提交和回滚操作。

ac9919e1c0f3baac380e4d702d7f3262.png

AT模式如何做到对业务的无侵入

  • 一阶段:

在一阶段,Seata 会拦截“业务 SQL”,首先解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”,然后执行“业务 SQL”更新业务数据,在业务数据更新之后,再将其保存成“after image”,最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。

56cc0626b08c2137c941f213a9314755.png
  • 二阶段提交:

二阶段如果是提交的话,因为“业务 SQL”在一阶段已经提交至数据库, 所以 Seata 框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。

80d5b2fc863b17a9c92df128f4d1ed2f.png
  • 二阶段回滚:

二阶段如果是回滚的话,Seata 就需要回滚一阶段已经执行的“业务 SQL”,还原业务数据。回滚方式便是用“before image”还原业务数据;但在还原前要首先要校验脏写,对比“数据库当前业务数据”和 “after image”,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理。

dbc8c1da8c0e34b830e4e0297c5450fa.png

AT 模式的一阶段、二阶段提交和回滚均由 Seata 框架自动生成,用户只需编写“业务 SQL”,便能轻松接入分布式事务,AT 模式是一种对业务无任何侵入的分布式事务解决方案。

当然官网对AT模式也进行了细致的讲解, 大家可以看下Seata官网的Seata AT模式。

Dubbo + Seata 实战案例

环境准备

Dubbo

docker-compose.yaml:

version: '3'

services:
  zookeeper:
    image: zookeeper
    ports:
      - 2181:2181
  admin:
    image: apache/dubbo-admin
    depends_on:
      - zookeeper
    ports:
      - 8080:8080
    environment:
      - admin.registry.address=zookeeper://zookeeper:2181
      - admin.config-center=zookeeper://zookeeper:2181
      - admin.metadata-report.address=zookeeper://zookeeper:2181
Seata

docker-compose.yaml:

version: "3"
services:
  seata-server:
    image: seataio/seata-server
    hostname: seata-server
    ports:
      - "8091:8091"
    environment:
      - SEATA_PORT=8091
      - STORE_MODE=file
MySQL
docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:latest

目录结构

bd288fc32f4f698859296c1d46deac21.png
  • Storage : 商品库存逻辑模块;

  • Account: 用户账户逻辑模块;

  • Order: 商品订单逻辑模块;

  • Business: 业务层逻辑模块;

下面我通过Storage模块来描述Dubbo + Seata的接入,其他模块,例如account, order模块的接入都是相同的。

Storage商品库存模块

项目目录
.
├── java
│   └── cn
│       └── mushuwei
│           └── storage
│               ├── SeataStorageApplication.java #应用SpringBoot启动类
│               ├── api
│               │   ├── StorageApi.java #库存调用Dubbo接口
│               │   └── dto
│               │       └── CommodityDTO.java #库存数据传输类
│               ├── config
│               │   └── SeataAutoConfig.java #Seata配置类
│               ├── dao
│               │   └── StorageDao.java #库存持久化类
│               ├── entity
│               │   └── StorageDO.java #库存持久化实体
│               ├── provider
│               │   └── StorageApiImpl.java #库存调用Dubbo接口实现类
│               └── service
│                   ├── StorageService.java #库存业务操作逻辑类
│                   └── impl
│                       └── StorageServiceImpl.java #库存业务操作逻辑实现类
└── resources
    ├── application.yml #应用配置文件
    ├── mybatis
    │   └── storage.xml #mybatis xml文件
    └── sql
        └── storage.sql #数据库表结构和初始化数据

15 directories, 12 files
Pom.xml
                
                <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-apiartifactId>
        dependency>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>log4j-over-slf4jartifactId>
        dependency>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>jul-to-slf4jartifactId>
        dependency>

                
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
                
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>${mysql.version}version>
        dependency>

                
        <dependency>
            <groupId>org.apache.dubbogroupId>
            <artifactId>dubbo-spring-boot-starterartifactId>
        dependency>

        
        <dependency>
            <groupId>org.apache.curatorgroupId>
            <artifactId>curator-frameworkartifactId>
        dependency>
        <dependency>
            <groupId>org.apache.curatorgroupId>
            <artifactId>curator-recipesartifactId>
        dependency>
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
        dependency>
        
        <dependency>
            <groupId>io.seatagroupId>
            <artifactId>seata-spring-boot-starterartifactId>
        dependency>
应用配置文件
# dubbo配置项,对应DubboConfigurationProperties 配置类
dubbo:
  application:
   
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值