2

分布式事务 —— SpringCloud Alibaba Seata - 低吟不作语

 11 months ago
source link: https://www.cnblogs.com/Yee-Q/p/17744259.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Seata 简介

传统的单体应用中,业务操作使用同一条连接操作不同的数据表,一旦出现异常就可以整体回滚。随着公司的快速发展、业务需求的变化,单体应用被拆分成微服务应用,原来的单体应用被拆分成多个独立的微服务,分别使用独立的数据源,业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证,但是全局的数据一致性问题无法保证。在微服务架构中,一次业务请求需要操作多个数据源或需要进行远程调用,就会产生分布式事务问题。

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务,Seata 为用户提供 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。AT 模式是 Seata 默认的工作模式,该模式是 XA 协议的演变。

关于分布式事务的知识可以参考:https://zhuanlan.zhihu.com/p/263555694

Seata 服务端

通过 https://github.com/seata/seata/releases 地址下载 Seata 安装包,本文使用的 Seata 版本是 seata-server-1.7.1

解压 seata-server-1.7.1 安装包,修改 conf/application.conf 文件

yaml
server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: D:\seata-server-1.7.1\logs\seata
  extend:
    logstash-appender:
      destination: 127.0.0.1:4560
    kafka-appender:
      bootstrap-servers: 127.0.0.1:9092
      topic: logback_to_logstash

console:
  user:
    username: seata
    password: seata
seata:
  config:
    # 使用nacos作为配置中心,seata将从nacos获取配置
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: 0178e474-2cfb-47c3-bded-da7cfa260f99
      group: springcloud-project
      data-id: seata-server.properties
  registry:
    # 使用nacos作为注册中心,seata将自身服务注册到nacos
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: 0178e474-2cfb-47c3-bded-da7cfa260f99
      group: springcloud-project
      application: seata-server
      cluster: default
  store:
    # 存储模式:
    # file模式为单机模式,全局事务会话信息内存中读写并持久化本地文件 rootdata,性能较高
    # db模式为高可用模式,全局事务会话信息通过db共享,相应性能会差
    # redis模式性能较高,存在事务信息丢失风险,需要提前配置适合当前场景的redis持久化配置
    mode: file
#  server:
#    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login

在 Nacos 控制台创建配置文件 seata-server.properties,注意分组和命名空间要与上述配置保持一致

具体配置项是从 script/config-center/config.txt 粘贴修改而来,这里只使用对我们有用的配置,主要是数据库配置信息

properties
#Transaction storage configuration, only for the server.
store.mode=db
store.lock.mode=db
store.session.mode=db

#These configurations are required if the `store mode` is `db`.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/test_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useAffectedRows=true
store.db.user=root
store.db.password=123
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

在上面配置的数据库内,执行 script/server/db 目录下的 sql 脚本,创建服务端所需的表

完成以后,即可进入 bin 目录使用脚本启动 Seata

Seata 客户端

为客户端微服务添加依赖

xml
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

配置文件添加如下配置

yaml
seata:
  enabled: true
  tx-service-group: test-seata-group # 自定义事务组名称,需要与下面service.vgroup-mapping中的一个映射保持一致
  service:
    vgroup-mapping:
      test-seata-group: default
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8847/nacos
      namespace: 0178e474-2cfb-47c3-bded-da7cfa260f99
      group: springcloud-project
      application: seata-server

Seata 默认使用 AT 模式,该模式需求每个客户端库内都存在一张 undo_log 表,用于回滚事务时临时记录数据

sql
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,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

在需要使用分布式事务的方法上添加注解 @GlobalTransactional,当方法内发生异常时,就可以带动所调用微服务进行回滚

java
@GlobalTransactional
public void create(Order order) {

    log.info("下单开始");
    orderDao.create(order);
    log.info("下单结束");

    log.info("开始扣减余额");
    server02FeignClient.accountIncrUsed(order.getUserId(), order.getMoney());
    log.info("扣减余额结束");

    log.info("开始扣减库存");
    server03FeignClient.storageIncrUsed(order.getProductId(), order.getCount());
    log.info("扣减库存结束");

    log.info("开始修改订单状态");
    orderDao.updateStatus(1, order.getId());
    log.info("修改订单状态结束");
}

配置完成,启动服务,即可开始测试


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK