栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

nacos+feign+seata 集成分布式事务,以及踩坑过程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

nacos+feign+seata 集成分布式事务,以及踩坑过程

这是一段完整的配置spring cloud +feign+nacos 项目下,增加 seata 的 AT 模式作为的分布式事务解决方案,同时希望可以通过这个流程下来,

可以看到我在过程中参考的信息来源,去总结如何引入框架,同时存在疑问信息,从哪些现有信息里找到解决方案的方式有些帮助。

版本信息:

springBoot:2.2.5.RELEASE

nacos:2.0 以上

seata:1.5.2

1、下载和初始化 seata 数据库

(1)下载

访问:

Releases · seata/seata · GitHub

下载找到Assets下的 seata-server 压缩包。

(2)初始化所需的 Mysql 数据库

此处示例用的是 mysql,还可以支持 oracle 和 postgresql

创建一个DB,此处命名为 db_seata,进入库中

执行解压缩文件中 seat/script/server/db/mysql.sql 的 SQL 语句

(3)为业务服务对应数据库添加 undo_log

这里有熟悉的,是不是很像 mysql 的undo_log 文件机制,seata 的实现其实也是模拟 mysql 的 undo_log 的实现方案去做到回滚的。

但是目前 seata 回滚的 sql 还是存在一些限制,详情可查阅: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;

2、修改启动的配置文件

seata/config/application.yml

参考的配置方式,来源于同级目录下 application.example.yml

里面针对各个类型的配置示例,都提供出来,包括以下的三点,

既然用到 nacos 和 mysql,那么配置中心、注册中心、store 干脆都使用上。

(1)修改配置中心

seata:

  config:

    type: nacos

    nacos:

      server-addr: 127.0.0.1:8848

      group : "SEATA_GROUP"

      namespace: ""

      dataId: "seataServer.properties"

      username: "nacos"

      password: "nacos"

参考:nacos

(2)修改注册中心

registry:

  type: nacos

  nacos:

    ##注册的服务名称

    application: seata-server

    ##nacos的地址端口

    server-addr: 127.0.0.1:8848

    ##此处注意自己的业务服务的 group 和 namespace 配置,匹配得到才能访问,这里仅仅举例

    group : "SEATA_GROUP"

    namespace: ""

    #对应的账号密码

    username: "nacos"

    password: "nacos"

(3)修改 DB 连接到 mysql

store:   

 # support: file 、 db 、 redis

    mode: db

    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

大致图样:

2、上传配置文件到 Nacos 的配置中心。

参考官方文档:nacos

进入目录 seata/script/config-center

(1)修改配置文件

修改 config.txt 里面的mode 为 db 数据库,并调整链接

(2)上传到nacos

方式一:

sh ${SEATAPATH}/script/config-center/nacos/nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 5a3c7d6c-f497-4d68-a71a-2e5e3340b3ca -u username -w password

//localhost -p 8848 --> nacos 的地址

//-g SEATA_GROUP -t  5a3c7d6c-f497-4d68-a71a-2e5e3340b3ca ---> 对应前面配置 nacos 的注册中心的 group 和 namespace,namespace 需要用业务服务的,若用的 public ,-t 这部分可删除

// -u username -w password -->username:nacos 账号,password:nacos 密码

sh ./script/config-center/nacos/nacos-config.sh -h 127.0.0.1 -p 8848 -g SEATA_GROUP -t 5a3c7d6c-f497-4d68-a71a-2e5e3340b3ca -u nacos -w nacos

(seata 和业务服务均需要在这个初始化完成后再启动)

方式二:

在对应nacos 创建一个 seataServer.properties 将配置信息,黏贴进去。

3、业务服务的配置

(1)添加依赖

prarent pom 添加依赖



    io.seata

    seata-spring-boot-starter

    1.5.2

    

        

            io.seata

            seata-all

        

    





    io.seata

    seata-all

    1.5.2

依赖关联回滚的服务添加依赖



    io.seata

    seata-spring-boot-starter

    1.5.2

(2)业务服务 application 文件修改

##这里和前方配置 seata 的配置文件是一致的

seata:

  config:

    # support: nacos, consul, apollo, zk, etcd3

    type: nacos

    nacos:

      server-addr: 127.0.0.1:8848

      group: "SEATA_GROUP"

      dataId: "seataServer.properties"

      username: "nacos"

      password: "nacos"

  registry:

    type: nacos

    nacos:

      ##注册的服务名称

      application: seata-server

      ##nacos的地址端口

      server-addr: 127.0.0.1:8848

      ##此处注意自己的业务服务的 group 和 namespace 配置,匹配得到才能访问,这里仅仅举例

      group : "SEATA_GROUP"

      ##对应的账号密码

      username: "nacos"

      password: "nacos"

若是配置为 dataId: "seataServer.properties",那么配置文件走的是这里,seata 的 application.yal 关于 mode 、store、决定生效取决于配置文件

(3)feign 的全局 xid 传输

通过全局配置,增加服务通信信息中,可以携带 seata 的 xid 进行传输

@Configuration

public class FeignSupportConfig {

  

  @Bean

  public RequestInterceptor requestInterceptor(){

    return new FeignBasicAuthRequestInterceptor();

  }

}


@Slf4j

public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {

  @Override

  public void apply(RequestTemplate requestTemplate) {

    requestTemplate.header(AsapConstants.DATA_SOURCE_CODE, AsapConstants.DATA_SOURCE);

    requestTemplate.header(AsapConstants.REQUEST_ID, TraceIdUtils.getTraceId());

    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

    if (ObjectUtils.isEmpty(requestAttributes)){

      return ;

    }

    ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;

    HttpServletRequest request = attributes.getRequest();

    Enumeration headerNames = request.getHeaderNames();

    //服务通信携带初始请求的 header

    if (headerNames != null) {

      while (headerNames.hasMoreElements()) {

        String name = headerNames.nextElement();

        String values = request.getHeader(name);

        // 跳过 content-length

        if ("content-length".equals(name)){

          continue;

        }

        requestTemplate.header(name, values);

      }

      //传递 seata 回滚 xid

      String xid = RootContext.getXID();

      requestTemplate.header(RootContext.KEY_XID, xid);


    } else {

      log.info("feign interceptor error header:{}", requestTemplate);

    }

  }

写 feign  通信接口时,添加配置文件依赖。

4、启动服务

seata-server.bat -p 8091 -h 127.0.0.1

启动成功后观察,启动的 seata web 服务时 7091 端口。 访问127.0.0.1:7091

业务服务启动后,结合  @GlobalTransactional 注解验证测试有无效果。

5、常见问题解决方案

Seata常见问题

6、遇到的问题

(1)服务部署过程中,seataServer.properties 的生效优先于seata的 config 文件application.yml ,过程中修改数据库的信息,仅仅修改这里不生效。

(2)由于项目中存在全局异常的处理,所以导致明明抛出异常但是事务还是不会回滚。

看 seata 的代码,response 的状态码异常才会 触发回滚。

7、常见 seata事务回滚失败的情况

(1)xid 在服务中传输存在问题,打日志检查,处理方式见第 3(2)。

(2)feign 的 db 没脸上,事务范围内,执行过程中在执行 sql 后打上 断点,然后登录seata 的管理台,检查是否存在事务和全局锁信息,有刚刚执行 Sql 的锁信息。

(3)全局异常导致失效,可以通过全局异常捕获过滤这些接口,或是通过手动执行事务的方式触发回滚。

try {

    TransactionManager manager = TransactionManagerHolder.get();

    manager.rollback(RootContext.getXID());

}catch (Exception e){

   log.error("手动回滚全局异常失败:{}",e);

}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1031568.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号