一、概述

在微服务架构下,虽然我们会尽量避免分布式事务,但是只要业务复杂的情况下这是一个绕不开的问题,如何保证业务数据一致性呢?本文主要介绍同步场景下使用SeataAT模式来解决一致性问题。

Seata阿里巴巴 开源的 一站式分布式事务解决方案 中间件,以 高效 并且对业务 0 侵入 的方式,解决 微服务 场景下面临的分布式事务问题

 

二、Seata介绍

整体事务逻辑是基于 两阶段提交 的模型,核心概念包括以下3个角色:

  • TM:事务的发起者。用来告诉 TC,全局事务的开始,提交,回滚。
  • RM:具体的事务资源,每一个 RM 都会作为一个分支事务注册在 TC。
  • TC:事务的协调者seata-server,用于接收我们的事务的注册,提交和回滚。

目前的Seata有两种模式可使用分别对应不同业务场景

2.1. AT模式

该模式适合的场景:

  • 基于支持本地 ACID 事务的关系型数据库。
  • Java 应用,通过 JDBC 访问数据库。

 

一个典型的分布式事务过程:

  1. TMTC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID
  2. XID 在微服务调用链路的上下文中传播。
  3. RMTC 注册分支事务,将其纳入 XID 对应全局事务的管辖。
  4. TMTC 发起针对 XID 的全局提交或回滚决议。
  5. TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。

 

2.2. MT模式

该模式逻辑类似TCC,需要 自定义实现 preparecommitrollback的逻辑,适合 非关系型数据库 的场景

 

三、Seata场景样例

模拟一个简单的用户下单场景,4个子工程分别是 Bussiness(事务发起者)Order(创建订单)Storage(扣减库存)Account(扣减账户余额)

3.1. 部署Seata的Server端

Discover注册、Config配置和Store存储模块默认都是使用file只能适用于单机,我们安装的时候分别改成使用nacosMysql以支持server端集群

3.1.1. 下载最新版本并解压

https://github.com/seata/seata/releases

 

3.1.2. 修改 conf/registry.conf 配置

注册中心和配置中心默认是file这里改为nacos;设置 registryconfig 节点中的typenacos,修改serverAddr为你的nacos节点地址。

registry {
type = "nacos" nacos {
serverAddr = "192.168.28.130"
namespace = "public"
cluster = "default"
}
} config {
type = "nacos" nacos {
serverAddr = "192.168.28.130"
namespace = "public"
cluster = "default"
}
}

 

3.1.3. 修改 conf/nacos-config.txt配置

  • 修改 service.vgroup_mapping 为自己应用对应的名称;如果有多个服务,添加相应的配置

默认组名为${spring.application.name}-fescar-service-group,可通过spring.cloud.alibaba.seata.tx-service-group配置修改

  • 修改 store.modedb,并修改数据库相关配置

 

3.1.4. 初始化seata的nacos配置

cd conf
sh nacos-config.sh 192.168.28.130

成功后在nacos的配置列表中能看到seata的相关配置

 

3.1.5. 初始化数据库

执行conf/db_store.sql中的脚本

 

3.1.6. 启动seata-server

sh bin/seata-server.sh -p 8091 -h 192.168.28.130

 

3.2. 应用配置

3.2.1. 初始化数据库

执行脚本 seata-demo.sql

需在业务相关的数据库中添加 undo_log 表,用于保存需要回滚的数据

 

3.2.2. 添加registry.conf配置

直接把 seata-server 中的registry.conf复制到每个服务中去即可,不需要修改

 

3.2.3. 修改配置

demo中的每个服务各自修改配置文件

  • bootstrap.yml 修改nacos地址
  • application.yml 修改数据库配置

 

3.2.4. 配置数据源代理

Seata是通过代理数据源实现分布式事务,所以需要配置io.seata.rm.datasource.DataSourceProxyBean,且是@Primary默认的数据源,否则事务不会回滚,无法实现分布式事务

public class DataSourceProxyConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
} @Primary
@Bean
public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
}

因为使用了mybatis的starter所以需要排除DataSourceAutoConfiguration,不然会产生循环依赖

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

 

3.2.5. 事务发起者添加全局事务注解

事务发起者 business-service 添加 @GlobalTransactional 注解

@GlobalTransactional
public void placeOrder(String userId) {
......
}

 

3.3. 测试

提供两个接口测试

  1. 事务成功:扣除库存成功 > 创建订单成功 > 扣减账户余额成功

    http://localhost:9090/placeOrder
  2. 事务失败:扣除库存成功 > 创建订单成功 > 扣减账户余额失败,事务回滚

    http://localhost:9090/placeOrderFallBack

 

3.4. demo下载地址

https://gitee.com/zlt2000/microservices-platform/tree/master/zlt-demo/seata-demo

 

推荐阅读

 

扫码关注有惊喜!

Spring Cloud同步场景分布式事务怎样做?试试Seata的更多相关文章

  1. Spring Cloud异步场景分布式事务怎样做?试试RocketMQ

    一.背景 在微服务架构中,我们常常使用异步化的手段来提升系统的 吞吐量 和 解耦 上下游,而构建异步架构最常用的手段就是使用 消息队列(MQ),那异步架构怎样才能实现数据一致性呢?本文主要介绍如何使用 ...

  2. Spring Cloud Gateway的动态路由怎样做?集成Nacos实现很简单

    一.说明 网关的核心概念就是路由配置和路由规则,而作为所有请求流量的入口,在实际生产环境中为了保证高可靠和高可用,是尽量要避免重启的,所以实现动态路由是非常有必要的:本文主要介绍 Spring Clo ...

  3. Spring Cloud第九篇 | 分布式服务跟踪Sleuth

    ​ ​本文是Spring Cloud专栏的第九篇文章,了解前八篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring Cl ...

  4. 【Spring Cloud】Spring Cloud Config 实现分布式配置中心

    Spring Cloud Config 实现分布式配置中心 一.分布式配置中心 分布式系统中,往往拥有大量的服务应用,而每个应用程序都需要有对应的配置文件来协助完成服务环境初始化.运行.因此生产了大量 ...

  5. Spring+JTA+Atomikos+mybatis分布式事务管理

    我们平时的工作中用到的Spring事务管理是管理一个数据源的.但是如果对多个数据源进行事务管理该怎么办呢?我们可以用JTA和Atomikos结合Spring来实现一个分布式事务管理的功能.了解JTA可 ...

  6. Spring Cloud(九):分布式配置中心和消息总线

    我们在Spring Cloud(七):使用SVN存储分布式配置中心文件和实现refresh中讲到,如果需要客户端获取到最新的配置信息需要执行refresh,我们可以利用webhook的机制每次提交代码 ...

  7. 事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理

    1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单 ...

  8. Spring事务隔离级别与传播机制详解,spring+mybatis+atomikos实现分布式事务管理

    原创说明:本文为本人原创作品,绝非他处转载,转账请注明出处 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). ...

  9. 构建Spring Cloud微服务分布式云架构

    大型企业分布式微服务云架构服务组件 实现模块化.微服务化.原子化.灰度发布.持续集成 commonservice zipkinSpring 日志收集工具包,封装了Dapper和log-based追踪以 ...

随机推荐

  1. java并发编程(七)----(JUC)ReadWriteLock

    前面我们已经分析过JUC包里面的Lock锁,ReentrantLock锁和semaphore信号量机制.Lock锁实现了比synchronized更灵活的锁机制,Reentrantlock是Lock的 ...

  2. [原创实践]IBM thinkpad T61制作和使用recovery光盘进行出厂系统恢复

    制作系统恢复盘 之前制作了系统恢复光盘,包含Product recovery 光盘1和光盘2,rescure and recovery光盘. 联想笔记本XP系统有一个硬盘分区是用来做恢复的,双击硬盘即 ...

  3. vue.js中ref及$refs的使用及讲解

    关于ref和$refs的用法及讲解,vue.js中文社区( https://cn.vuejs.org/v2/api/#ref )是这么讲解的: ref 被用来给元素或子组件注册引用信息,引用信息将会注 ...

  4. python --- 零碎

    1.匿名输出: lambda x : print(x))(100) #冒号前输入量 ,冒号后是输出量结果:100 2.导入调用其他python文件: test1.py #第一个python文件 def ...

  5. golang 中获取字符串个数

    golang 中获取字符串个数 在 golang 中不能直接用 len 函数来统计字符串长度,查看了下源码发现字符串是以 UTF-8 为格式存储的,说明 len 函数是取得包含 byte 的个数 // ...

  6. Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Job Manager 启动

    Job Manager 启动 https://t.zsxq.com/AurR3rN 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...

  7. 从60分到85分——SD-WAN进阶教程(下)

    本文为<从60分到85分——SD-WAN进阶教程>的下篇,上篇请跳转https://www.sdnlab.com/20683.html. (续上文)Enterprise Oriented ...

  8. node爬虫的几种简易实现方式

    说到爬虫大家可能会觉得很NB的东西,可以爬小电影,羞羞图,没错就是这样的.在node爬虫方面,我也是个新人,这篇文章主要是给大家分享几种实现node 爬虫的方式.第一种方式,采用node,js中的 s ...

  9. MonkeyRunner 第一天

    1.安装集成Android SDK的环境(如Eclipse),主要是为了android的模拟器,安装python编译环境,MonkeyRunner是基于Jython 2.使用Eclipse打开Andr ...

  10. 《C# 7.0核心技术指南》到货

    前几天有大佬推荐本书,并且折扣相当的划算,随入手一本.