SpringCloud Alibaba Seata est collecté

1. Introduction

Adresse du site officiel: http://seata.io/zh-cn/

1. Concept

Seata est une solution de transaction distribuée open source, dédiée à la fourniture de services de transaction distribués simples et performants dans l'architecture de microservices.

2. Traitement

ID de transaction XID: ID de transaction unique au monde

Transaction Coordinator (TC): Maintient le statut des transactions globales et des succursales, et dirige la validation ou l'annulation des transactions globales.

Transaction Manager ™: définissez la portée des transactions globales: démarrez des transactions globales, validez ou annulez des transactions globales.

Resource Manager (RM): Gérez les ressources pour le traitement des transactions de la succursale, parlez à TC pour enregistrer les transactions de la succursale et rapportez le statut des transactions de la succursale, et pilotez la validation ou l'annulation des transactions de la succursale.

image

  1. TM s'applique à TC pour démarrer une transaction globale, la transaction globale est créée avec succès et un XID unique au monde est généré
  2. XID se propage dans le contexte du lien d'appel du microservice
  3. RM enregistre les transactions des succursales auprès de TC et les inclut sous la juridiction des transactions globales correspondantes XID
  4. TM lance une résolution globale de soumission ou de restauration pour XID à TC
  5. TC planifie toutes les transactions des succursales sous la juridiction de XID pour répondre aux demandes de soumission ou d'annulation

Deuxièmement, l'installation de Seata-Server

1. Télécharger

http://seata.io/zh-cn/blog/download.html Choisissez la version spécifiée à télécharger (j'utilise la 0.9.0 ici)

2. Modifiez le fichier de configuration

Modifier seata / conf / file.conf

#将service中修改group
vgroup_mapping.my_test_tx_group = "my_group"
#将store模块修改为db并修改数据连接,将conf目录下的db_store.sql文件导入到数据库中
mode = "db"
db {
    datasource = "dbcp"
    db-type = "mysql"
    driver-class-name = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://127.0.0.1:3306/seata"
    user = "root"
    password = "123456"
}

Modifier seata / conf / registry.conf

registry {
  type = "nacos"
  nacos {
    serverAddr = "localhost:8848"
    namespace = ""
    cluster = "default"
 }

Trois, application Seata

1. Service de commande

Code source: seata-order-service2001

a, configurez pom

<!--nacos-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--seata-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>seata-all</artifactId>
            <groupId>io.seata</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-all</artifactId>
    <version>0.9.0</version>
</dependency>
<!--feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--web-actuator-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--mysql-druid-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.37</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.0.0</version>
</dependency>

View Code

b, configurez yaml

server:
  port: 2001

spring:
  application:
    name: seata-order-service
  cloud:
    alibaba:
      seata:
        #自定义事务组名称需要与seata-server中的对应
        tx-service-group: my_group
    nacos:
      discovery:
        server-addr: localhost:8848
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/seata_order
    username: root
    password: 123456

feign:
  hystrix:
    enabled: false

logging:
  level:
    io:
      seata: info

mybatis:
  mapperLocations: classpath:mapper/*.xml

View Code

c, ajoutez file.conf (identique à la configuration de seata-server)

transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  #thread factory for netty
  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"
    # netty boss thread size,will not be used for UDT
    boss-thread-size = 1
    #auto default pin or 8
    worker-thread-size = 8
  }
  shutdown {
    # when destroy server, wait seconds
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}

service {

  vgroup_mapping.my_group = "default"

  default.grouplist = "127.0.0.1:8091"
  enableDegrade = false
  disable = false
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
  disableGlobalTransaction = false
}

client {
  async.commit.buffer.limit = 10000
  lock {
    retry.internal = 10
    retry.times = 30
  }
  report.retry.count = 5
  tm.commit.retry.count = 1
  tm.rollback.retry.count = 1
}

## transaction log store
store {
  ## store mode: file、db
  mode = "db"

  ## file store
  file {
    dir = "sessionStore"

    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    max-branch-session-size = 16384
    # globe session size , if exceeded throws exceptions
    max-global-session-size = 512
    # file buffer size , if exceeded allocate new buffer
    file-write-buffer-cache-size = 16384
    # when recover batch read size
    session.reload.read_size = 100
    # async, sync
    flush-disk-mode = async
  }

  ## database store
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "dbcp"
    ## mysql/oracle/h2/oceanbase etc.
    db-type = "mysql"
    driver-class-name = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://127.0.0.1:3306/seata"
    user = "root"
    password = "123456"
    min-conn = 1
    max-conn = 3
    global.table = "global_table"
    branch.table = "branch_table"
    lock-table = "lock_table"
    query-limit = 100
  }
}
lock {
  ## the lock store mode: local、remote
  mode = "remote"

  local {
    ## store locks in user's database
  }

  remote {
    ## store locks in the seata's server
  }
}
recovery {
  #schedule committing retry period in milliseconds
  committing-retry-period = 1000
  #schedule asyn committing retry period in milliseconds
  asyn-committing-retry-period = 1000
  #schedule rollbacking retry period in milliseconds
  rollbacking-retry-period = 1000
  #schedule timeout retry period in milliseconds
  timeout-retry-period = 1000
}

transaction {
  undo.data.validation = true
  undo.log.serialization = "jackson"
  undo.log.save.days = 7
  #schedule delete expired undo_log in milliseconds
  undo.log.delete.period = 86400000
  undo.log.table = "undo_log"
}

## metrics settings
metrics {
  enabled = false
  registry-type = "compact"
  # multi exporters use comma divided
  exporter-list = "prometheus"
  exporter-prometheus-port = 9898
}

support {
  ## spring
  spring {
    # auto proxy the DataSource bean
    datasource.autoproxy = false
  }
}

View Code

d, ajoutez registry.conf (identique à la configuration de seata-server)

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    serverAddr = "localhost:8848"
    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 = ""
  }
  consul {
    serverAddr = "127.0.0.1:8500"
  }
  apollo {
    app.id = "seata-server"
    apollo.meta = "http://192.168.1.204:8801"
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.conf"
  }
}

View Code

e, appel Fegin (ici l'un des comptes est pris comme exemple)

@FeignClient(value = "seata-account-service")
public interface AccountService {

    @RequestMapping("/account/decrease")
    public CommonResult decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);

}

View Code

f, service de transaction

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    OrderDao orderDao;
    @Autowired
    AccountService accountService;
    @Autowired
    StorageService storageService;

    @Override
    @GlobalTransactional(name = "my-order-test",rollbackFor = Exception.class) //加注解使用全局的事务,name 为事务名称不重复就行
    public Long create(Order order) {
        log.info("=========================下订单,开始");
        orderDao.create(order);
        log.info("=========================下订单,完成");

        log.info("=========================减库存,开始");
        storageService.decrease(order.getProductId(), order.getCount());
        log.info("=========================减库存,完成");

        log.info("=========================减积分,开始");
        accountService.decrease(order.getUserId(), order.getMoney());
        log.info("=========================减积分,完成");

        log.info("=========================订单状态修改,开始");
        orderDao.update(order.getId(),1);
        log.info("=========================订单状态修改,完成");

        return order.getId();
    }
}

View Code

g, commencer la classe

View Code

2. Service d'inventaire

Code source: seata-storage-service2002

Identique aux étapes de configuration de a, b, c, d, g dans le service de commande

3. Service de compte

Code source: seata-account-service2003

Mêmes étapes de configuration que le service d'inventaire

Quatrièmement, l'analyse principale de Seata

Document de référence: http://seata.io/zh-cn/docs/overview/what-is-seata.html

1. Mode AT

Une étape

1,解析SQL语义,找到"业务SQL"要更新的业务数据,在业务数据被更新前,将其保存成"before image"
2,执行"业务SQL"更新业务数据,在业务数更新之后
3,将其保存成"after image",最后生成行锁。
以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。

image

Engagement en deux phases

Parce que "Business SQL" dans une phase a été soumis à la base de données, si seata frame juste pour enregistrer un instantané d'une étape et de supprimer des données de verrouillage de ligne , terminer le nettoyage des données peut être.

image

Restauration en deux étapes

Si la deuxième étape est une restauration, seata doit annuler le "SQL métier" qui a été exécuté lors de la première étape pour restaurer les données métier.

La façon de revenir en arrière consiste à utiliser «avant l'image» pour restaurer les données d'entreprise, mais avant la restauration, vérifiez d'abord les écritures incorrectes, comparez les «données d'entreprise actuelles de la base de données» et «l'image après»

Si les deux données sont parfaitement cohérentes, cela signifie qu'il n'y a pas d'écriture sale et que les données métier peuvent être restaurées. Si elles sont incohérentes, cela signifie qu'il y a une écriture sale, et si une écriture sale se produit, un traitement manuel est nécessaire.

image

Je suppose que tu aimes

Origine blog.csdn.net/doubututou/article/details/109289551
conseillé
Classement