seata 1.1.0 入门,简介_seata1.1.0使用文档-程序员宅基地

技术标签: 分布式事务  

 

1.SeaTa简介

SeaTa 是阿里开源的可供商用的分布式事务框架 前身Fescar , java程序

 

1.1亮点

  • 应用层基于SQL解析实现了自动补偿,从而最大程度的降低业务侵入性;
  • 将分布式事务中TC(事务协调者)独立部署,负责事务的注册、回滚;
  • 通过全局锁实现了写隔离与读隔离
  • 多种事务模式 : AT、TCC、SAGA 事务模式

 

1.2 SeaTa相关概念

  • TC :事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
  • TM:控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
  • RM:控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。
  • TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。

 

1.3执行流程

 

  1. TM 向 TC 申请开启一个全局事务,TC 创建全局事务后返回全局唯一的 XID,XID 会在全局事务的上下文中传播;
  2. RM 向 TC 注册分支事务,该分支事务归属于拥有相同 XID 的全局事务;
  3. TM 向 TC 发起全局提交或回滚;
  4. TC 调度 XID 下的分支事务完成提交或者回滚

 

1.4 详细参数

https://seata.io/zh-cn/docs/user/configurations.html

 

1.5性能损耗

  • 一条Update的SQL,则需要全局事务xid获取(与TC通讯)
  • before image(解析SQL,查询一次数据库)
  • after image(查询一次数据库)
  • insert undo log(写一次数据库)
  • before commit(与TC通讯,判断锁冲突)

这些操作都需要一次远程通讯RPC,而且是同步的。另外undo log写入时blob字段的插入性能也是不高的。每条写SQL都会增加这么多开销,粗略估计会增加5倍响应时间(二阶段虽然是异步的,但其实也会占用系统资源,网络、线程、数据库)

 

 

 

2.准备工作

 

1.server端工作

 

1.TC (Seate-server ) 下载

2.建表

  • TC需要新建三张表
    • db_store.sql
    • 各个表对应功能
      • 全局事务---global_table
      • 分支事务---branch_table
      • 全局锁-----lock_table

 

3.修改配置文件

  • seata/conf/file.conf server服务 的日志记录方式,数据库连接信息
## transaction log store, only used in seata-server
store {
  ## store mode: file、db 事务日志存储模式
  mode = "db"   
# 服务端配置
 service {
# 分组名称 需要和client端一致 chuangqi-steata
  vgroup_mapping.chuangqi-steata = "chuangqi-steata"
  chuangqi-steata.grouplist = "127.0.0.1:8091"
# 降级开关 默认关闭
  enableDegrade = false
  disable = false
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
}
  ## 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) etc.
    datasource = "dbcp"
    ## mysql/oracle/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://localhost:3306/seata"
    user = "root"
    password = "root"
    minConn = 1
    maxConn = 10
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
  

 

  • seata/conf/registry.conf 不同注册中心和配置中心 file 单机本地版
registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "file"




  nacos {
    serverAddr = "localhost"
    namespace = ""
    cluster = "default"
  }
  eureka {
    serviceUrl = "http://localhost:8761/eureka"
    application = "default"
    weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = "0"
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
  }
  etcd3 {
    cluster = "default"
    serverAddr = "http://localhost:2379"
  }
  sofa {
    serverAddr = "127.0.0.1:9603"
    application = "default"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    cluster = "default"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  }
  file {
    name = "file.conf"
  }
}




config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "file"




  nacos {
    serverAddr = "localhost"
    namespace = ""
    group = "SEATA_GROUP"
  }
  consul {
    serverAddr = "127.0.0.1:8500"
  }
  apollo {
    app.id = "seata-server"
    apollo.meta = "http://192.168.1.204:8801"
    namespace = "application"
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.conf"
  

 

4.启动

seata/bin/seata-server.sh

nohup sh seata-server.sh -h xx.xx.xx.xx -p 8091 -m db -n 1 -e test &
-h: 注册到注册中心的ip
-p: Server rpc 监听端口
-m: 全局事务会话信息存储模式,file、db,优先读取启动参数
-n: Server node,多个Server时,需区分各自节点,用于生成不同区间的transactionId,以免冲突
-e: 多环境配置参考 http://seata.io/en-us/docs/ops/multi-configuration-isolation.html

 

 

 

2.client端工作

 

2.1项目添加依赖 (单选) 

  • 依赖seata-all 手动配置较多
  • 依赖seata-spring-boot-starter,支持yml配置
  • 依赖spring-cloud-alibaba-seata,内部集成了seata,并实现了xid传递
  • client 版本与 server端版本一致

 

 

2.2项目新建undo_log表

db_undo_log.sql

 

2.3 增加配置文件 (1.1.0版本)

  • yml文件
seata:
  enabled: true
  application-id: account-api  # 项目标识
  tx-service-group: chuangqi-steat # seata分组名称
  enable-auto-data-source-proxy: true # 开启数据源自动代理
  use-jdk-proxy: false # 使用的代理方式
  client:
    rm:
      async-commit-buffer-limit: 1000
      report-retry-count: 5
      table-meta-check-enable: false
      report-success-enable: false
      lock:
        retry-interval: 10
        retry-times: 30
        retry-policy-branch-rollback-on-conflict: true
    tm:
      commit-retry-count: 5
      rollback-retry-count: 5
    undo:
      data-validation: true
      log-serialization: jackson
      log-table: undo_log
    log:
      exceptionRate: 100
  service:
    vgroup-mapping:
      my_test_tx_group: default
    grouplist:
      default: 127.0.0.1:8091
    #enable-degrade: false
    #disable-global-transaction: false
  transport:
    shutdown:
      wait: 3
    thread-factory:
      boss-thread-prefix: NettyBoss
      worker-thread-prefix: NettyServerNIOWorker
      server-executor-thread-prefix: NettyServerBizHandler
      share-boss-worker: false
      client-selector-thread-prefix: NettyClientSelector
      client-selector-thread-size: 1
      client-worker-thread-prefix: NettyClientWorkerThread
      worker-thread-size: default
      boss-thread-size: 1
    type: TCP
    server: NIO
    heartbeat: true
    serialization: seata
    compressor: none
    enable-client-batch-send-request: true
  config:
    type: file
    consul:
      server-addr: 127.0.0.1:8500
    apollo:
      apollo-meta: http://192.168.1.204:8801
      app-id: seata-server
      namespace: application
    etcd3:
      server-addr: http://localhost:2379
    nacos:
      namespace:
      serverAddr: localhost
      group: SEATA_GROUP
    zk:
      server-addr: 127.0.0.1:2181
      session-timeout: 6000
      connect-timeout: 2000
      username: ""
      password: ""
  registry:
    type: file
    consul:
      cluster: default
      server-addr: 127.0.0.1:8500
    etcd3:
      cluster: default
      serverAddr: http://localhost:2379
    eureka:
      application: default
      weight: 1
      service-url: http://localhost:8761/eureka
    nacos:
      cluster: default
      server-addr: localhost
      namespace:
    redis:
      server-addr: localhost:6379
      db: 0
      password:
      cluster: default
      timeout: 0
    sofa:
      server-addr: 127.0.0.1:9603
      application: default
      region: DEFAULT_ZONE
      datacenter: DefaultDataCenter
      cluster: default
      group: SEATA_GROUP
      addressWaitTime: 3000
    zk:
      cluster: default
      server-addr: 127.0.0.1:2181
      session-timeout: 6000
      connect-timeout: 2000
      username: ""
      password: ""

 

2.4 开启数据源代理

  • 关闭spring自动代理
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)
  • 注入数据源
@Bean
@Autowired
public SqlSessionFactory sqlsessionfactory(HikariDataSource dataSource, Configuration configuration) throws Exception {
    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(dataSource);


    sqlSessionFactoryBean.setPlugins(new Interceptor[]{new PageInterceptor()});
    sqlSessionFactoryBean.setConfiguration(configuration);
    return sqlSessionFactoryBean.getObject();
}


@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariDataSource dataSource() {
   return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
    @Primary
    @Bean("dataSource")
    public DataSourceProxy dataSource(DataSource druidDataSource){
        return new DataSourceProxy(druidDataSource);
    }

 

2.4 初始化GlobalTransactionScanner

  • 手动
       public GlobalTransactionScanner globalTransactionScanner() {
           String applicationName = this.applicationContext.getEnvironment().getProperty("spring.application.name");
           String txServiceGroup = this.seataProperties.getTxServiceGroup();
           if (StringUtils.isEmpty(txServiceGroup)) {
               txServiceGroup = applicationName + "-fescar-service-group";
               this.seataProperties.setTxServiceGroup(txServiceGroup);
           }
   
           return new GlobalTransactionScanner(applicationName, txServiceGroup);
       }
  • 自动,引入seata-spring-boot-starter、spring-cloud-alibaba-seata等jar

 

 

 

2.5根据项目架构 配置 XID 传递

  • 手动 参考源码integration文件夹下的各种rpc实现 module
  • 自动 springCloud用户可以引入spring-cloud-alibaba-seata,内部已经实现xid传递

 

 

2.6 使用

  • 1.@GlobalTransaction 全局事务注解 项目中要实现分布式事务的接口加入
  • 2.@GlobalLock 防止脏读和脏写,又不想纳入全局事务管理时使用。(不需要rpc和xid传递等成本)

 

3.注意事项

 

1.server端

  • file模式为单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高;
  • db模式为高可用模式,全局事务会话信息通过db共享,相应性能差些
  • file模式可直接启动 , 无需多余配置

 

2.client端

  • restTemplate RPC调用时 : SeataFilter ,SeataRestTemplateAutoConfiguration 需要交给spring管理 , 扫描包路径记得添加

 

 

4.各个模式介绍

 

1.AT模式

 

1.0简介

  • 简单上手
  • 二阶段提交

 

1.1 前提

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

 

1.2实现

  • 二阶段提交演变 , 整体基于本地事务 + 全局锁 + 本地锁 实现 回滚通过undo_log进行反向补偿
  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
  • 二阶段:
    • 提交异步化,非常快速地完成。
    • 回滚通过一阶段的回滚日志进行反向补偿。

 

 

1.3 步骤

  • 一阶段开启事务时 首先获取本地锁 然后开始走业务逻辑
    • 本地锁获取失败 不断重试
  • 一阶段提交前 , 首先尝试获取该条记录的全局锁
    • 获取全局锁失败 不能提交本地事务 , 重试获取全局锁 (获取 默认 10ms一次 , 重试30次)
      • client.rm.lock.retryInterval 校验或占用全局锁重试间隔 默认10 单位ms
      • client.rm.lock.retryTimes 校验或占用全局锁重试次数 默认30
      • 重试后仍未获取到全局锁 , 回滚本地事务 , 释放本地锁
    • 获取成功 一阶段事务执行
  • 二阶段事务执行
    • commit : 直接执行
    • rollback : 首先重新获取 该条记录的本地锁 , 然后执行反向补偿操作 实现回滚

 

 

1.4 脏写,脏读问题

1.写隔离

  • 上述案例, 在tx1 二阶段提交之前 tx2可以获取到tx1还未全局提交的数据 ,tx2提交事务会脏写
    • 解决 :
    • tx1二阶段提交前一直拥有全局锁 , 回滚时需要获取本地锁 ,
    • tx2 拥有本地锁 , 一阶段提交前需要获取到全局锁
    • tx1回滚获取本地锁会不断重试 , 那么tx2获取全局锁会超时
    • tx2超时 -> 回滚本地事务 , 释放本地锁
    • tx1获取到本地锁 -> 事务回滚

2.读隔离

  • 上述案例 , tx2是否可以读到 tx1还未全局提交的数据
    • 在数据库本地事务隔离级别 读已提交(Read Committed) 或以上的基础上,Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。
    • 通过 SELECT FOR UPDATE实现
    • SELECT FOR UPDATE 会去申请全局锁
      • 获取失败 则重试获取 直到全局锁获取到
  • 对性能消耗较大
  • @GlobalLock 注解解决脏读幻读问题 (不生成undo_log)

 

1.5工作原理

# 分支事务的sql
update product set name = 'GTS' where name = 'TXC';

一阶段

  • 解析sql , 通过条件获取到查询前镜像数据
    • select id, name, since from product where name = 'TXC'; 获取到查询前镜像
  • 执行sql
  • 获取执行后镜像 , 根据查询前镜像结果 , 通过主键 定位查询后镜像
    • select id, name, since from product where id = 1`;
  • 把镜像前后数据 以及业务sql等信息 组成一条 回滚记录 插入到undo_log中
{
	"branchId": 641789253,
	"undoItems": [{
		"afterImage": {
			"rows": [{
				"fields": [{
					"name": "id",
					"type": 4,
					"value": 1
				}, {
					"name": "name",
					"type": 12,
					"value": "GTS"
				}, {
					"name": "since",
					"type": 12,
					"value": "2014"
				}]
			}],
			"tableName": "product"
		},
		"beforeImage": {
			"rows": [{
				"fields": [{
					"name": "id",
					"type": 4,
					"value": 1
				}, {
					"name": "name",
					"type": 12,
					"value": "TXC"
				}, {
					"name": "since",
					"type": 12,
					"value": "2014"
				}]
			}],
			"tableName": "product"
		},
		"sqlType": "UPDATE"
	}],
	"xid": "xid:xxx"
}
  • 提交前,向 TC 注册分支:申请 product 表中,主键值等于 1 的记录的 全局锁 。
  • 本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。
  • 将本地事务提交的结果上报给 TC。

 

二阶段-回滚

  • 收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。
  • 通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。
  • 数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理
  • 根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:
update product set name = 'TXC' where id = 1;
  • 提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。

 

二阶段-提交

  • 收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。
  • 异步任务阶段的分支提交请求将异步和批量地删除相应 UNDO LOG 记录。

 

1.6特点

  • 改造成本低 , cloud项目基本只需要添加配置文件 , 新增注解
  • 普通springboot项目 - 添加配置文件 , 实现XID传递
  • 隔离性

 

2.TCC模式

 

2.0简介

  • 二阶段提交

 

2.1前提

  • 每个分支事务需要具备
    • 一阶段 prepare 方法 (本地提交)
    • 二阶段 commit 或 rollback 方法
  • TCC模式不依赖底层数据源的事务支持
    • 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
    • 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
    • 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
  • TCC其实就是 自定义本地事务 加入了全局事务的管理

 

2.2特点

  • 性能好 , 没有多余的操作, 只有TC管理
  • 隔离性
  • 业务改动大 , 开发困难

 

 

3.Saga模式

 

3.0简介

  • SEATA提供的长事务解决方案
  • 业务流程中每个参与者都提交本地事务
  • 当出现某一个参与者失败则补偿前面已经成功的参与者
  • 一阶段正向服务 和 二阶段补偿服务都由业务开发实现

 

3.1前提

  • 开发一阶段正向业务 和 二阶段补偿业务

 

3.2特点

  • 适合长事务
  • 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口
  • 一阶段提交本地事务,无锁,高性能
  • 事件驱动架构,参与者可异步执行,高吞吐
  • 不保证隔离性

 

3.3实现

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/q690080900/article/details/104944123

智能推荐

2D医学图像分割大模型:SAM-Med2D-程序员宅基地

文章浏览阅读2.1k次,点赞21次,收藏29次。[_sam-med2d

深圳Java培训:Javaweb现在流行用什么框架?_深圳流行开发框架-程序员宅基地

文章浏览阅读126次。深圳Java培训:Javaweb现在流行用什么框架?Java是开源的,框架很多,这些框架都能解决特定的问题,提高开发效率、简化我们的代码复杂度,现在除了很多大家通用的一些主流框架外,很多公司针对自己的业务会自定义一些公司内部的框架,当然作为学习者我们首先要清楚Javaweb都有哪些框架需要学习。回答这个问题首先要看我们的项目规模,对于”体量”较小的单应用项目,和需要处理海量数据、高并发的分布式..._深圳流行开发框架

云卷云舒_云卷云舒任逍遥 博客-程序员宅基地

文章浏览阅读107次。_云卷云舒任逍遥 博客

ESP32开发之蓝牙播放mp3_esp32 蓝牙音频-程序员宅基地

文章浏览阅读1.6k次。esp32 蓝牙播放mp3_esp32 蓝牙音频

Python数据结构与算法(5)--搜索和排序,你掌握了多少-程序员宅基地

文章浏览阅读797次,点赞24次,收藏27次。Map():创建一个空映射,返回空映射对象;put(key, val):将key‐val关联对加入映射中,如果key已存在,将val替换旧关联值;get(key):给定key,返回关联的数据值,如不存在,则返回None;del:通过del map[key]的语句形式删除key‐val关联;len():返回映射中key‐val关联的数目;in:通过key in map的语句形式,返回key是否存在于关联中,布尔值#我们用一个HashTable类来实现ADT Map,该类包含了两个列表作为成员。

linux0.12-6-4(head.s)-程序员宅基地

文章浏览阅读440次。学习记录,打卡。卷起来! (-:

随便推点

RSA的运用和前后端签名的一些看法_rsa puk pvk-程序员宅基地

文章浏览阅读1.1k次。RSA的运用和前后端签名的一些看法RSA在验签过程的使用场景分析不按照上述方式验签会造成的问题日常前后端交互简化版的RSA应用分析RSA在验签过程的使用场景分析 RSA的文章有很多。原理性学术性的对于我这样普通的码农毫无意义,对于我来说,我只想知道为什么我们要用RSA,以及什么 情况下我们需要使用它?这是一篇粗浅且迅速入门的文章。首先,我要介绍RSA验签的流程,稍后再分析为啥要这样做。..._rsa puk pvk

SpringMVC ajax请求参数为json时注意事项_ajax json请求对参数有要求吗-程序员宅基地

文章浏览阅读230次。SpringMVC Ajax请求参数为json时的几个注意事项如果请求参数为json,请求时必须加上contentType:‘application/json;charset=UTF-8’① data写成标准json字符串格式*’{’‘name:“tom”,“age”:39}’*,key必须加引号,单引号/双引号均可,但必须得加,大括号外边也必须加上引号否则会报错,控制台会报错,报错如下警告 [http-nio-8082-exec-12] org.springframework.web.ser_ajax json请求对参数有要求吗

php数组函数-程序员宅基地

文章浏览阅读130次。数组函数一、数组操作的基本函数数组的键名和值array_values($arr); 获得数组的值array_keys($arr); 获得数组的键名array_flip($arr); 数组中的值与键名互换(如果有重复前面的会被后面的覆盖)in_array("apple",$arr); 在数组中检索applearray_search("apple",$arr); 在数组中检索apple ,如...

MySQL远程操作记录删除_mysql 远程访问-程序员宅基地

文章浏览阅读341次。1、改表法。可能是你的帐号不允许从远程登陆,只能在localhost。这个时候只要在localhost的那台电脑,登入mysql后,更改 "mysql" 数据库里的 "user" 表里的 "host" 项,从"localhost"改称"%"mysql-uroot-pvmwaremysql>usemysql;mysql>updateusersethost='%'w...

python修饰符作用_python函数修饰符@的使用-程序员宅基地

文章浏览阅读334次。python函数修饰符@的作用是为现有函数增加额外的功能,常用于插入日志、性能测试、事务处理等等。创建函数修饰符的规则:(1)修饰符是一个函数(2)修饰符取被修饰函数为参数(3)修饰符返回一个新函数(4)修饰符维护被维护函数的签名例子1:被修饰函数不带参数def log(func):def wrapper():print('log开始 ...')func()print('log结束 ...')re...

cocos creator 十三水棋牌_福州十三水源码下载-程序员宅基地

文章浏览阅读4.4k次。下载地址:https://download.csdn.net/download/u012443049/10556049_福州十三水源码下载