什么是分布式事务

单体应用被拆分成微服务应用,原来的三个模块被拆成三个独立的应用,分别使用三个独立的数据源
业务操作需要调用三个服务来完成,此时每个服务内部的数据一致性由本地事务来保证,但是全局的数据一致性问题没法保证。

一句话:

一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题

Seata简介

Seata 是什么

Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。

官网地址

https://seata.io/zh-cn/

Seata能干吗

一个典型的分布式事务过程:

  1. 分布式事务处理过程的一ID+三组件模型

    1. Transaction ID XID 全局事务id
    2. 3组件概念
      1. Transaction Coordinator(TC) 事务协调器:维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
      2. Transaction Manager(TM) 事务管理器:控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议;
      3. Resource Manager(RM) 资源管理器:控制分支事务,负责分支注册,状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚

        Seata 的执行流程

  2. TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID;

  3. XID在微服务调用链路的上下文中传播;
  4. RM向TC 注册分支事务,将其纳入XID对应全局事务的管辖;
  5. TM向TC发起针对XID的全局提交或回滚决策;
  6. TC调度XID下管辖的全部分支事务完成提交或回滚请求。

    Seata去哪下

    发布说明: https://github.com/seata/seata/releases

    Seata 怎么玩

    在单机事务: @Transactional
    在分布式事务: @GlobalTransactional

    SEATA的分布式交易解决方案

Seata的安装

下载地址

https://seata.io/zh-cn/blog/download.html

修改 file.conf 配置文件

1. 备份原文件

  1. cp file.conf file.conf.bak

2. 主要修改: 自定义事务组名称 + 事务日志存储模式为db + 数据库连接信息

  1. ## transaction log store, only used in seata-server
  2. store {
  3. ## store mode: file、db、redis
  4. mode = "db"
  5. ## file store property
  6. file {
  7. ## store location dir
  8. dir = "sessionStore"
  9. # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
  10. maxBranchSessionSize = 16384
  11. # globe session size , if exceeded throws exceptions
  12. maxGlobalSessionSize = 512
  13. # file buffer size , if exceeded allocate new buffer
  14. fileWriteBufferCacheSize = 16384
  15. # when recover batch read size
  16. sessionReloadReadSize = 100
  17. # async, sync
  18. flushDiskMode = async
  19. }
  20. ## database store property
  21. db {
  22. ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
  23. datasource = "druid"
  24. ## mysql/oracle/postgresql/h2/oceanbase etc.
  25. dbType = "mysql"
  26. driverClassName = "com.mysql.jdbc.Driver"
  27. url = "jdbc:mysql://127.0.0.1:3306/seata"
  28. user = "root"
  29. password = "123456"
  30. minConn = 5
  31. maxConn = 30
  32. globalTable = "global_table"
  33. branchTable = "branch_table"
  34. lockTable = "lock_table"
  35. queryLimit = 100
  36. maxWait = 5000
  37. }
  38. ## redis store property
  39. redis {
  40. host = "127.0.0.1"
  41. port = "6379"
  42. password = ""
  43. database = "0"
  44. minConn = 1
  45. maxConn = 10
  46. queryLimit = 100
  47. }
  48. }

创建Seata所需数据库,并创建表结构

  1. -- the table to store GlobalSession data
  2. drop table if exists `global_table`;
  3. create table `global_table` (
  4. `xid` varchar(128) not null,
  5. `transaction_id` bigint,
  6. `status` tinyint not null,
  7. `application_id` varchar(32),
  8. `transaction_service_group` varchar(32),
  9. `transaction_name` varchar(128),
  10. `timeout` int,
  11. `begin_time` bigint,
  12. `application_data` varchar(2000),
  13. `gmt_create` datetime,
  14. `gmt_modified` datetime,
  15. primary key (`xid`),
  16. key `idx_gmt_modified_status` (`gmt_modified`, `status`),
  17. key `idx_transaction_id` (`transaction_id`)
  18. );
  19. -- the table to store BranchSession data
  20. drop table if exists `branch_table`;
  21. create table `branch_table` (
  22. `branch_id` bigint not null,
  23. `xid` varchar(128) not null,
  24. `transaction_id` bigint ,
  25. `resource_group_id` varchar(32),
  26. `resource_id` varchar(256) ,
  27. `lock_key` varchar(128) ,
  28. `branch_type` varchar(8) ,
  29. `status` tinyint,
  30. `client_id` varchar(64),
  31. `application_data` varchar(2000),
  32. `gmt_create` datetime,
  33. `gmt_modified` datetime,
  34. primary key (`branch_id`),
  35. key `idx_xid` (`xid`)
  36. );
  37. -- the table to store lock data
  38. drop table if exists `lock_table`;
  39. create table `lock_table` (
  40. `row_key` varchar(128) not null,
  41. `xid` varchar(96),
  42. `transaction_id` long ,
  43. `branch_id` long,
  44. `resource_id` varchar(256) ,
  45. `table_name` varchar(32) ,
  46. `pk` varchar(36) ,
  47. `gmt_create` datetime ,
  48. `gmt_modified` datetime,
  49. primary key(`row_key`)
  50. );

修改registry.conf

  1. registry {
  2. # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  3. type = "nacos"
  4. nacos {
  5. application = "seata-server"
  6. serverAddr = "127.0.0.1:8848"
  7. group = "SEATA_GROUP"
  8. namespace = ""
  9. cluster = "default"
  10. username = ""
  11. password = ""
  12. }
  13. eureka {
  14. serviceUrl = "http://localhost:8761/eureka"
  15. application = "default"
  16. weight = "1"
  17. }
  18. redis {
  19. serverAddr = "localhost:6379"
  20. db = 0
  21. password = ""
  22. cluster = "default"
  23. timeout = 0
  24. }
  25. zk {
  26. cluster = "default"
  27. serverAddr = "127.0.0.1:2181"
  28. sessionTimeout = 6000
  29. connectTimeout = 2000
  30. username = ""
  31. password = ""
  32. }
  33. consul {
  34. cluster = "default"
  35. serverAddr = "127.0.0.1:8500"
  36. }
  37. etcd3 {
  38. cluster = "default"
  39. serverAddr = "http://localhost:2379"
  40. }
  41. sofa {
  42. serverAddr = "127.0.0.1:9603"
  43. application = "default"
  44. region = "DEFAULT_ZONE"
  45. datacenter = "DefaultDataCenter"
  46. cluster = "default"
  47. group = "SEATA_GROUP"
  48. addressWaitTime = "3000"
  49. }
  50. file {
  51. name = "file.conf"
  52. }
  53. }
  54. config {
  55. # file、nacos 、apollo、zk、consul、etcd3
  56. type = "file"
  57. nacos {
  58. serverAddr = "127.0.0.1:8848"
  59. namespace = ""
  60. group = "SEATA_GROUP"
  61. username = ""
  62. password = ""
  63. }
  64. consul {
  65. serverAddr = "127.0.0.1:8500"
  66. }
  67. apollo {
  68. appId = "seata-server"
  69. apolloMeta = "http://192.168.1.204:8801"
  70. namespace = "application"
  71. }
  72. zk {
  73. serverAddr = "127.0.0.1:2181"
  74. sessionTimeout = 6000
  75. connectTimeout = 2000
  76. username = ""
  77. password = ""
  78. }
  79. etcd3 {
  80. serverAddr = "http://localhost:2379"
  81. }
  82. file {
  83. name = "file.conf"
  84. }
  85. }

启动测试

如果看到如下的输出,则Seata服务端启动成功!
image.png