SpringCloud Alibaba之Seata分布式事务搭建AT模式

官方文档

Seata简介 (详细文档可以查看官方文档)

Seata 是什么?

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
Seata事务管理中有三个重要的角色:
TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

在这里插入图片描述
在这里插入图片描述

搭建Seata-server服务

1.下载Seata-server服务端

下载地址: https://github.com/seata/seata/releases
在这里插入图片描述
目录结构
在这里插入图片描述

1.配置Seata-server数据源

== 注意: seata 在1.5.1以前配置文件被分尾了两部分:file.conf registry.conf
1.5.1 以后统一放在了 application.yaml中,类容配置内容是一样的 ==

通过提供的模板进行修改,修改完成后赋值一份将名字改为application.yml覆盖默认文件
文件路径: \seata\conf/application.example.yml
在这里插入图片描述

默认为file,改为db存储 下面是需求修改的部分以mysql为例:
根据需求修改db连接和创建seata数据库,执行创建表sql文件
文件位置: “\seata\script\server\db\mysql.sql”
在这里插入图片描述

1. 修改数据源
在这里插入图片描述
2. 修改注册中心地址
在这里插入图片描述
3. 修改注册中心地址
在这里插入图片描述

在nacos中创建的seata.properties配置文件需要的配置相关配置对应的功能可以查看官方文档
文件路径 \seata\script\config-center\config.txt
找到文件 copy配置粘贴到nacos创建好的配置文件中
主要需要修改的部分就是数据源的配置
在这里插入图片描述

1.5以上版本需要加上

# 管理界面账号密码 1.5以上版本不加会报错
console:
  user:
    username: seata
    password: seata

 security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000        

完整的yaml配置

server:
  port: 7091

spring:
  application:
    name: seata-server

# 管理界面账号密码 1.5以上版本不加会报错
console:
  user:
    username: seata
    password: seata    

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

seata:
  config:
    # support: nacos 、 consul 、 apollo 、 zk  、 etcd3
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: 
      group: SEATA_GROUP
      username: nacos
      password: nacos
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key: ""
      #secret-key: ""
      data-id: seataServer.properties
    consul:
      server-addr: 127.0.0.1:8500
      acl-token:
      key: seata.properties
    apollo:
      appId: seata-server
      apollo-meta: http://192.168.1.204:8801
      apollo-config-service: http://192.168.1.204:8080
      namespace: application
      apollo-access-key-secret:
      cluster: seata
    zk:
      server-addr: 127.0.0.1:2181
      session-timeout: 6000
      connect-timeout: 2000
      username:
      password:
      node-path: /seata/seata.properties
    etcd3:
      server-addr: http://localhost:2379
      key: seata.properties
  registry:
    # support: nacos 、 eureka 、 redis 、 zk  、 consul 、 etcd3 、 sofa
    type: nacos
    preferred-networks: 30.240.*
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
      namespace:
      cluster: default
      username:
      password:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key: ""
      #secret-key: ""
    eureka:
      service-url: http://localhost:8761/eureka
      application: default
      weight: 1
    redis:
      server-addr: localhost:6379
      db: 0
      password:
      cluster: default
      timeout: 0
    zk:
      cluster: default
      server-addr: 127.0.0.1:2181
      session-timeout: 6000
      connect-timeout: 2000
      username: ""
      password: ""
    consul:
      cluster: default
      server-addr: 127.0.0.1:8500
      acl-token:
    etcd3:
      cluster: default
      server-addr: http://localhost:2379
    sofa:
      server-addr: 127.0.0.1:9603
      application: default
      region: DEFAULT_ZONE
      datacenter: DefaultDataCenter
      cluster: default
      group: SEATA_GROUP
      address-wait-time: 3000
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login
  server:
    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
    max-commit-retry-timeout: -1
    max-rollback-retry-timeout: -1
    rollback-retry-timeout-unlock-enable: false
    enable-check-auth: true
    enable-parallel-request-handle: true
    retry-dead-threshold: 130000
    xaer-nota-retry-timeout: 60000
    recovery:
      handle-all-session-period: 1000
    undo:
      log-save-days: 7
      log-delete-period: 86400000
    session:
      branch-async-queue-size: 5000 #branch async remove queue size
      enable-branch-async-remove: false #enable to asynchronous remove branchSession
  #旧版本这部分是放在 file.conf 中的   
  store:
    # support: file 、 db 、 redis
    mode: db
    session:
      mode: db
    lock:
      mode: db
    file:
      dir: sessionStore
      max-branch-session-size: 16384
      max-global-session-size: 512
      file-write-buffer-cache-size: 16384
      session-reload-read-size: 100
      flush-disk-mode: async
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
      user: mysql
      password: mysql
      min-conn: 5
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 100
      max-wait: 5000
    redis:
      mode: single
      database: 0
      min-conn: 1
      max-conn: 10
      password:
      max-total: 100
      query-limit: 100
      single:
        host: 127.0.0.1
        port: 6379
      sentinel:
        master-name:
        sentinel-hosts:
  metrics:
    enabled: false
    registry-type: compact
    exporter-list: prometheus
    exporter-prometheus-port: 9898
  transport:
    rpc-tc-request-timeout: 30000
    enable-tc-server-batch-send-response: false
    shutdown:
      wait: 3
    thread-factory:
      boss-thread-prefix: NettyBoss
      worker-thread-prefix: NettyServerNIOWorker
      boss-thread-size: 1
初始化配置到nacos

初始化seata的配置脚本在源码目录 /seata/script/config-center/nacos ,执行以下命令初始化配置到nacos,nacos要先开启

sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t default -u nacos -w nacos

配置完成后确保数据库和nacos是正常状态,这时候就可以直接启动seata服务了,默认端口是8091
在这里插入图片描述
可以在nacos上检测seata服务是否注册成功.
在这里插入图片描述

微服务整合seata

引入依赖
        <!--   spring.cloud.alibaba  版本管理器     -->
  <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-alibaba-dependencies</artifactId>
     <version>2.2.9.RELEASE</version>
     <type>pom</type>
     <scope>import</scope>
  </dependency>
<dependency>    
<groupId>com.alibaba.cloud</groupId>    
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>    
<exclusions>               
<exclusion>            
<artifactId>seata-spring-boot-starter</artifactId>          
<groupId>io.seata</groupId>        
</exclusion>    
</exclusions>
</dependency>
<!--seata starter 采用1.5.2版本-->
<dependency>    
<groupId>io.seata</groupId>    
<artifactId>seata-spring-boot-starter</artifactId>    
<version>1.5.2</version>
</dependency>
在对应的业务数据库中创建一张undo_log表,每个需要配置事务处理的业务库都应该构建回滚表
-- 注意此处0.7.0+ 增加字段 context
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

在对应服务的配置文件中加上seata的相关配置

## 客户端seata的相关配置
seata:
  ## 是否开启seata,默认true
  enabled: true
  ## seata事务组的名称,一定要和config.txt(nacos)中配置的相同 service.vgroupMapping.default_tx_group=default
  tx-service-group: default_tx_group
  ##开启动态代理
  enable-auto-data-source-proxy: true
  ## 配置中心的配置
  config:
    ## 使用类型nacos
    type: nacos
    ## nacos作为配置中心的相关配置,需要和server在同一个注册中心下
    nacos:
      ## 命名空间,需要server端(registry和config)、nacos配置client端(registry和config)保持一致
      namespace: 7a7581ef-433d-46f3-93f9-5fdc18239c65
      ## 地址
      server-addr: localhost:8848
      ## 组, 需要server端(registry和config)、nacos配置client端(registry和config)保持一致
      group: SEATA_GROUP
      ## 用户名和密码
      username: nacos
      password: nacos
      data-id: seata.properties
  registry:
    type: nacos
    nacos:
      ## 这里的名字一定要和seata服务端中 的名称相同,默认是seata-server
      application: seata-server
      server-addr: 127.0.0.1:8848
      ## 需要server端(registry和config)、nacos配置client端(registry和config)保持一致
      group: SEATA_GROUP
      namespace: 7a7581ef-433d-46f3-93f9-5fdc18239c65
      username: nacos
      password: nacos

使用分布式事务处理业务

我们只需要使用一个 == @GlobalTransactional == 注解在业务方法上
== @GlobalLock +@Transactional ==也可以实现

写隔离

一阶段本地事务提交前,需要确保先拿到 全局锁 。
拿不到 全局锁 ,不能提交本地事务。
拿 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。
以一个示例来说明:
两个全局事务 tx1 和 tx2,分别对 a 表的 m 字段进行更新操作,m 的初始值 1000。
tx1 先开始,开启本地事务,拿到本地锁,更新操作 m = 1000 - 100 = 900。本地事务提交前,先拿到该记录的 全局锁 ,本地提交释放本地锁。 tx2 后开始,开启本地事务,拿到本地锁,更新操作 m = 900 - 100 = 800。本地事务提交前,尝试拿该记录的 全局锁 ,tx1 全局提交前,该记录的全局锁被 tx1 持有,tx2 需要重试等待 全局锁 。
在这里插入图片描述

tx1 二阶段全局提交,释放 全局锁 。tx2 拿到 全局锁 提交本地事务。
在这里插入图片描述
如果 tx1 的二阶段全局回滚,则 tx1 需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。
此时,如果 tx2 仍在等待该数据的 全局锁,同时持有本地锁,则 tx1 的分支回滚会失败。分支的回滚会一直重试,直到 tx2 的 全局锁 等锁超时,放弃 全局锁 并回滚本地事务释放本地锁,tx1 的分支回滚最终成功。
因为整个过程 全局锁 在 tx1 结束前一直是被 tx1 持有的,所以不会发生 脏写 的问题。

读隔离

在数据库本地事务隔离级别 读已提交(Read Committed) 或以上的基础上,Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。

如果应用在特定场景下,必需要求全局的 读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。

通过在SELECT 语句末尾拼接上 FOR UPDATE 关键字
在这里插入图片描述

SELECT FOR UPDATE 语句的执行会申请 全局锁 ,如果 全局锁 被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到 全局锁 拿到,即读取的相关数据是 已提交 的,才返回。
出于总体性能上的考虑,Seata 目前的方案并没有对所有 SELECT 语句都进行代理,仅针对 FOR UPDATE 的 SELECT 语句。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值