Seata初试采坑

作者: KingdomCoder | 来源:发表于2020-03-13 15:30 被阅读0次

    背景:

    公司采用dubbo的分布式服务,现在业务上遇到了分布式事物的问题,和同事讨论改过几个分布式的开源框架,最终采用了seata,seata的性能相对比较客观,但是回滚情境下,性能下降特别厉害,这个与seata的网络IO和数据IO多次交互相关。具体各种分布式事物管理的开源框架推荐一篇文章可以参考:“若干分布式事务框架”与“我的偏见”( 测试/分析),此处我们部署搭建是最新的1.1.0版本。

    采坑之路:

    1.Seata Server搭建部署

    服务端搭建,可以直接从seata开源社区下载最新版本,下载的文件可以直接在服务器解压部署,自行修改配置文件自己的环境参数主要是下图的file.conf和register.conf

    配置文件说明
    register.conf 主要配置如下:
    registry {
      # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
      # 注册中心采用的zk
      type = "zk"
    
      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,127.0.0.1:2183,127.0.0.1:2183"
        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
      # 这边的配置没有对接配置中心所以采用file的方式配置,这边配置之后会自动读取file文件的配置
      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"
      }
    }
    
    

    file.conf 配置如下

    store {
      ## store mode: file、db
      # 存储我们设置为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) etc.
        datasource = "druid"
        ## mysql/oracle/h2/oceanbase etc.
        dbType = "mysql"
        driverClassName = "com.mysql.jdbc.Driver"
        url = "jdbc:mysql://127.0.01:3306/seata"
        user = "admin"
        password = "admin"
        minConn = 1
        maxConn = 10
        globalTable = "global_table"
        branchTable = "branch_table"
        lockTable = "lock_table"
        queryLimit = 100
      }
    }
    

    修改相关的配置文件之后,可以直接在bin目录下执行相应的shell启动脚本。

    2.客户端配置

    • 依赖引用
    <dependency>
         <groupId>io.seata</groupId>
         <artifactId>seata-spring-boot-starter</artifactId>
         <version>1.1.0</version>
       </dependency>
       # seata zk连接主要依赖zkclient
       <dependency>
         <groupId>com.101tec</groupId>
         <artifactId>zkclient</artifactId>
         <version>0.11</version>
       </dependency>
    
    • yml 配置
    seata:
     enabled: true
     application-id: ${spring.application.name}  # 可以自定义
     tx-service-group: seller_seata_group # 此处的名称一定要与 vgroup-mapping下配置的参数保持一致
     registry:
       file:
        #因为seata版本驼峰参数映射有问题导致,seata的zk配置参数设置不上导致异常,所以采用了file方式
         name: registry-test.conf 
     service:
       grouplist:
           # seata seaver的 地址配置,此处可以集群配置是个数组
           default: 127.0.0.1:8091
       vgroup-mapping:
         # key一定要与tx-service-group一致
         seller_seata_group: default
    # 这边自动代理关掉是因为,, seata源码中SeataDataSourceBeanPostProcessor的初始化要比我的datasource初始话晚,导致datasoure不会被包装为代理类,此处我自己代码做了处理
     enableAutoDataSourceProxy: false
    

    配置注意点:

    • tx-service-group配置的值一定要与vgroup-mapping配置下的key保持一致,否则会异常

      [2020-03-13 14:44:00,188] ERROR [timeoutChecker_2      ]                                    i.s.c.r.n.NettyClientChannelManager:170 - [ ] no available service 'null' found, please make sure registry config correct
      
      

      具体异常发生在NettyClientChannelManager,在执行void reconnect(String transactionServiceGroup)时去查询transactionServiceGroup下的服务是查询不到的,所以打印了错误日志,也就是意味着此时seata的事物管理是失效的。

    • 最新seata-spring-boot-starter支持在yml中直接配置相关注册中心的一些参数配置,目前1.1.0存在驼峰转化上的异常,这边跟踪源码得出的兵并且已经提了issues,于1.2.0 版本修复,临时解决方案为seata.registry.file.name=register.conf注册中心配置为读取file文件register.conf

      
      registry {
        # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
        # 注册中心采用的zk
        type = "zk"
        zk {
          cluster = "default"
          # 集群配置采用,隔开
          serverAddr = "127.0.0.1:2181,127.0.0.1:2183,127.0.0.1:2183"
          session.timeout = 6000
          connect.timeout = 2000
        }
      }
      
    • DataSource需要包装成seat的DataSourceProxy代理,这边seata-spring-boot-starter 是通过Spring的BeanPostProcessor后置在类初始化之后去包装DataSource,相关源码可参照SeataDataSourceBeanPostProcessor,但是我遇到的情况是我的DataSource初始化要在这个SeataDataSourceBeanPostProcessor之前,public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansExceptio 拦截不到DataSource类型的对象,所以这边我们选择了关闭掉数据源自动代理,(如果开启的情况下,自行去封装代理DataSourceProxy,代码会抛异常)自己去实现代理的封装,此处采用了aop拦截去处理的。主要代码如下:

      @Configuration
      @Import({DataSourceAspect.class})
      public class DataSourceConfig {
      
          @Autowired
          private DbPasswordCallback dbPasswordCallback;
      
      
          @Bean
          @ConfigurationProperties("spring.datasource.druid")
          public DataSource dataSource() {
              DruidDataSource druidDataSource = new DruidDataSource();
              druidDataSource.setPasswordCallback(dbPasswordCallback);
              druidDataSource.setConnectionInitSqls(Collections.singletonList("set names utf8mb4;"));
              return druidDataSource;
          }
      
          @Bean
          public DataSourceProxy dataSourceProxy(DataSource dataSource){
              return new DataSourceProxy(dataSource);
          }
      
      }
      
      @Aspect
      public class DataSourceAspect {
      
          @Resource
          private ConfigurableEnvironment environment;
      
          @Pointcut("@annotation(org.springframework.context.annotation.Bean)")
          public void pointCut() {
          }
      
          @Around(value = "pointCut() && @annotation(configProperties)")
          public Object around(ProceedingJoinPoint joinPoint, ConfigurationProperties configProperties) throws Throwable {
              Object object = joinPoint.proceed();
              if (null != object && (object instanceof DataSource)) {
                  DataSource dataSource = (DataSource) object;
                  bindDataSource(dataSource, configProperties.value());
                  return new DataSourceProxy(dataSource);
              }
              return object;
          }
      
          private void bindDataSource(DataSource dataSource, String name) {
              Binder binder = Binder.get(environment);
              Bindable<DataSource> bindable = Bindable.ofInstance(dataSource);
              binder.bind(name, bindable);
          }
      
      }
      
      
      • 采用最新的seata版本,mysql驱动版本是有要求的,存在版本不兼容的问题,这个文档是没有说明的,我们需要升级到mysql驱动至少在6.0以上,否则遇到时间处理上,会异常我这边提了issues

    通过上面的一系列操作,我们就可以正常的开始我们的seata之旅了。

    扫一扫关注

    相关文章

      网友评论

        本文标题:Seata初试采坑

        本文链接:https://www.haomeiwen.com/subject/jpklshtx.html