分布式事务介绍

事务的四个属性(ACID):原子性、一致性、隔离型、持久性
本地事务:
@Transational:大多数场景下,我们的应用都只需要操作单一的数据库,这种情况下的事务称之为本地事务。本地事务的ACID特性是数据库直接提供支持的。
分布式事务:

什么是Seata

是一款开源的分布式事务解决发噶,致力于提高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式。
官网:http://seata.io/zh-cn/index.html
源码:https://github.com/seata/seata
官方demo:https://github.com/seata/seata-samples

Seata的三大角色

  • TC (Transaction Coordinator) - 事务协调者 维护全局和分支事务的状态,驱动全局事务提交或回滚
  • TM (Transaction Manager) - 事务管理器 定义全局事务的范围:开始全局事务、提交或回滚全局事务
  • RM (Resource Manager) - 资源管理器管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚

其中,TC为单独部署的Server服务端,TM和RM为嵌入到应用中的Client客户端。

二阶段提交协议

2PC两阶段提交协议,顾名思义,分为两个阶段:Prepare和commit
prepare:提交事务请求,基本流程如下:
Seata - 图1
过程:

  1. 询问 协调者向所有参与者发送事务请求,询问是否可执行事务操作,然后等待各个参与者的响应
  2. 执行 各个参与者接收到协调者事务请求后,执行事务操作,并将Undo和Redo的信息记录
  3. 响应 如果参与者成功执行了事务并写入Undo和Redo信息,则向协调者返回YES响应,否则返回NO响应,参与者也可能宕机,不参与响应

Commit:执行事务提交

  1. commit请求 协调者向所有参与者发送commit请求
  2. 事务提交 参与者收到commit请求后,执行事务提交,提交完成后释放事务执行期占用的所有资源
  3. 反馈结果: 参与者执行事务提交后向协调者发送ACK响应
  4. 完成事务 接收到所有参与者的ACK响应后,完成事务提交

中断事务
在执行Prepare步骤过程中,如果某些参与者执行事务失败,宕机或与协调者之间的网络中断,那么协调者就无法收到所有参与者的YES响应,或者某个参与者返回了NO响应。此时,协调者就会进入回退流程,对事务进行会退。流程如下入红色部分(将commit请求替换成红色的RollBack请求)

分布式解决方案:AT模式

是一种物侵入的分布式事务的解决方案,阿里的seata框架实现了该模式。在AT模式下,用户只需要关注自己的业务SQL,用户的业务SQL作为一阶段,Seata框架会自动生成事务的二阶段提交和回滚操作
Seata - 图2

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

  • 一阶段:
    在一阶段。Seata会拦截“业务SQL”,首先解析SQL语义,找到“业务SQL”需要更新的数据。在业务数据被更新钱,将其保存成”before image”,然后执行业务 SQL更新业务数据,在业务数据更新之后,在将其保存成“after image”。最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了操作的原子性
    Seata - 图3
  • 二阶段提交
    二阶段如果提交的话,因为业务SQL在一阶段已经提交到数据库,所以Seata框架只需要将一阶段保存的快照数据和行锁删掉,完成数据清理即可
    Seata - 图4
  • 二阶段回滚
    二阶段如果是回滚的话,Seata就需要回滚一阶段已经执行的业务SQL,还原业务数据,回滚方式便是用before image 还原业务数据;但在还原前要首先要校验脏写,对比数据库当前业务数据和after image,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要人工处理。
    Seata - 图5

分布式解决方案:TCC模式

需要用户根据自己的业务场景实现Try、Confirm和Cancel三个操作;事务发起方在一阶段执行Try方式,在二阶段提交执行Confirm方法,二阶段回滚操作执行Cancel方法
Seata - 图6
Seata - 图7

可靠消息最终一致性方案

Seata - 图8

Seata的AT模式原理

Seata服务搭建-db数据源

环境部署文档

Seata Server(TC环境部署)

Server端存储模式(store.mode)支持三种

  • file:单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高(默认)
  • db:高可用模式,全局事务会话信息通过db共享,响应性能差些

    • 修改安装目录下的/conf/file.conf文件,修改对应的模式为mode=db,修改数据库的连接信息```

      transaction log store, only used in seata-server

      store {

      store mode: file、db、redis

      修改这里的模式为数据库模式(db)

      mode = “db”

      file store property

      file {

      store location dir

      dir = “sessionStore”

      branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions

      maxBranchSessionSize = 16384

      globe session size , if exceeded throws exceptions

      maxGlobalSessionSize = 512

      file buffer size , if exceeded allocate new buffer

      fileWriteBufferCacheSize = 16384

      when recover batch read size

      sessionReloadReadSize = 100

      async, sync

      flushDiskMode = async }

      database store property

      修改数据库的信息

      db {

      the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.

      datasource = “druid”

      mysql/oracle/postgresql/h2/oceanbase etc.

      dbType = “mysql”

      新旧版本的数据库所用的驱动是不同的

      driverClassName = “com.mysql.cj.jdbc.Driver” url = “jdbc:mysql://62.234.130.20:3306/seata_server” user = “ecology” password = “192612” minConn = 5 maxConn = 30 globalTable = “global_table” branchTable = “branch_table” lockTable = “lock_table” queryLimit = 100 maxWait = 5000 }

      redis store property

      redis { host = “127.0.0.1” port = “6379” password = “” database = “0” minConn = 1 maxConn = 10 queryLimit = 100 }

      } ```

  • 通过查看资源找到对应版本下的/script/server/db/..对应版本的数据库脚本语句,在上述新建的数据库中执行
    • redis:Seata-server1.3及以上版本支持,性能较高,存在事务信息丢失风险,请提前配置适合当前场景的redis持久化配置
      资源目录
    • client:存放client端sql脚本,参数配置
    • config-center:各个配置中心参数导入脚本,config.txt(包含server和client,原名为nacos-config.txt)为通用文件
    • server:server端数据库脚本及各个容器配置

db存储模式+Nacos(注册&配置中心)

下载安装包

Seata服务搭建-nacos

Nacos配置中心文档
Nacos注册中心文档

配置Nacos注册中心 负责事务参与者(微服务)和TC通信

将seata server 注册到Nacos、修改conf目录下的registry.conf配置文件
Seata - 图9

修改对应的配置中心

Seata - 图10

配置参数同步到Nacos

执行下载的scirpt中的nacos-config.sh的脚本
若是nacos开启了权限,注册的时候需要带有用户名和密码
出现一下文字说明注册成功

nacos-config.sh需要从源码工程上获取

  1. Set transport.serialization=seata successfully
  2. Set transport.compressor=none successfully
  3. Set metrics.enabled=false successfully
  4. Set metrics.registryType=compact successfully
  5. Set metrics.exporterList=prometheus successfully
  6. Set metrics.exporterPrometheusPort=9898 successfully
  7. =========================================================================
  8. Complete initialization parameters, total-count:79 , failure-count:0
  9. =========================================================================

Seata - 图11
执行的命令:sh nacos-config.sh -p 8847
参数说明:

  • -h:host,默认值是localhost
  • -p:port,默认值是8848
  • -g:配置分组,默认值为“SEATA_GROUP”
  • -t:租户信息,对应nacos的命名空间ID字段,默认值为空

配置完各种各种信息就可以启动服务

./seata-server.sh,端口是8091

分布式事务代码搭建

声明式服务的实现:@GlobalTransactional
接入微服务应用
业务场景:
用户下单,整个业务有三个微服务构成

  • 订单服务:根据采购需求创建订单
  • 库存服务:对给定的商品和扣除库存数量

启动seata server端,seata server使用nacos作为配置中心和注册中心
配置微服务整合seata
第一步:添加依赖

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
  4. </dependency>

第二步:各微服务对应的数据库中添加undo_log表
第三步: 修改register.conf,配置nacos作为register.type&config.type,对应的seata_server也使用nacos
注意:需要指定group=”SEATA_GROUP”,因为seata server端指定了group=”SEATA_GROUP”必须保持一致

Client搭建

运行原理总结