Seata安装与基础概念概诉(无坑版)

Seata安装与基础概念概诉(无坑版)

什么是分布式事务

如下图所示:分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

注意:本篇文章所讲的分布式事务特指在多个服务同时访问多个数据源的事务处理机制,请注意它与DTP 模型中“分布式事务”的差异。DTP 模型所指的“分布式”是相对于数据源而言的,并不涉及服务。本节所指的“分布式”是相对于服务而言的,如果严谨地说,它更应该被称为“在分布式服务环境下的事务处理机制”。

在这里插入图片描述

说人话

就是说在我们的系统体量还没有达到一定的规模的时候,我们单体架构是能够支撑起来所有的服务请求,此时所有对于数据库的操作都在一个库中,此时无论是出错的回滚还是说异常的处理也更加容易处理。

但是在业务逻辑更加复杂的情况下,很多时候我们都是采用RPC远端调用来完成业务逻辑的拆分,将不同的业务逻辑和功能模块进行拆分,使得其在各自实现自己的逻辑的情况下还能够为其他子应用提供服务,这也是目前为止市面上上常用到的对于业务逻辑增加的应对方法**,但是导致的问题就是,在不同的子模块中,我们无法保证在本地事务成功之后,调用其他服务是否成功**,不成功数据能否进行一个正常的回滚,所以也就引入了分布式事务-使其能够在不同的服务和不同的数据源中保证数据的一致性。

CAP原理

既然讨论到了分布式事务,就不得不来简单概述一下CAP原理,其最开始起源于在 2000 年 7 月,是加州大学伯克利分校的 Eric Brewer 教授于“ACM 分布式计算原理研讨会(PODC)”上提出的一个猜想。

在这里插入图片描述

两年之后,麻省理工学院的 Seth Gilbert 和 Nancy Lynch 以严谨的数学推理证明了 CAP 猜想。自此,CAP 正式从猜想变为分布式计算领域所公认的著名定理。这个定理里描述了一个分布式的系统中,涉及共享数据问题时,以下三个特性最多只能同时满足其中两个:

  • 一致性(Consistency):代表数据在任何时刻、任何分布式节点中所看到的都是符合预期的。一致性在分布式研究中是有严肃定义、有多种细分类型的概念,以后讨论分布式共识算法时,我们还会再提到一致性,那种面向副本复制的一致性与这里面向数据库状态的一致性严格来说并不完全等同,具体差别我们将在后续分布式共识算法中再作探讨。
  • 可用性(Availability):代表系统不间断地提供服务的能力,理解可用性要先理解与其密切相关两个指标:可靠性(Reliability)和可维护性(Serviceability)。可靠性使用平均无故障时间(Mean Time Between Failure,MTBF)来度量;可维护性使用平均可修复时间(Mean Time To Repair,MTTR)来度量。可用性衡量系统可以正常使用的时间与总时间之比,其表征为:A=MTBF/(MTBF+MTTR),即可用性是由可靠性和可维护性计算得出的比例值,譬如 99.9999%可用,即代表平均年故障修复时间为 32 秒。
  • 分区容忍性(Partition Tolerance):代表分布式环境中部分节点因网络原因而彼此失联后,即与其他节点形成“网络分区”时,系统仍能正确地提供服务的能力。

但是仅仅论述概念,对于CAP的理解来说还是比较难的,下面我们以一个实际的案例(如下场景案例)来说明,这三种不同的特质对于分布式系统来说意味着什么。

场景案例:
Fenix’s Bookstore 是一个在线书店。每当一本书被成功售出时,需要确保以下三件事情被正确地处理:
1 用户的账号扣减相应的商品款项。
2 商品仓库中扣减库存,将商品标识为待配送状态。
3 商家的账号增加相应的商品款项。

如下图所示,一个用户购买一本书籍的过程将由账号服务、商家服务和库存服务对应各自集群中的某一个节点来完成响应。
在这里插入图片描述
在这套系统中,每一个单独的服务节点都有自己的数据库(这里是为了便于说明问题的假设,在实际生产系统中,一般应避免将用户余额这样的数据设计成存储在多个可写的数据库中),假设某次交易请求分别由“账号节点 1”、“商家节点 2”、“仓库节点 N”联合进行响应。当用户购买一件价值 100 元的商品后,账号节点 1 首先应给该用户账号扣减 100 元货款,它在自己数据库扣减 100 元很容易,但它还要把这次交易变动告知本集群的节点 2 到节点 N,并要确保能正确变更商家和仓库集群其他账号节点中的关联数据,此时将面临以下可能的情况。

  • 如果该变动信息没有及时同步给其他账号节点,将导致有可能发生用户购买另一商品时,被分配给到另一个节点处理,由于看到账号上有不正确的余额而错误地发生了原本无法进行的交易,此为一致性问题。
  • 如果由于要把该变动信息同步给其他账号节点,必须暂时停止对该用户的交易服务,直至数据同步一致后再重新恢复,将可能导致用户在下一次购买商品时,因系统暂时无法提供服务而被拒绝交易,此为可用性问题。
  • 如果由于账号服务集群中某一部分节点,因出现网络问题,无法正常与另一部分节点交换账号变动信息,此时服务集群中无论哪一部分节点对外提供的服务都可能是不正确的,整个集群能否承受由于部分节点之间的连接中断而仍然能够正确地提供服务,此为分区容忍性。

以上还仅仅涉及了账号服务集群自身的 CAP 问题,对于整个 站点来说,它更是面临着来自于账号、商家和仓库服务集群带来的 CAP 问题,譬如,用户账号扣款后,由于未及时通知仓库服务中的全部节点,导致另一次交易中看到仓库里有不正确的库存数据而发生超售。又譬如因涉及仓库中某个商品的交易正在进行,为了同步用户、商家和仓库的交易变动,而暂时锁定该商品的交易服务,导致了的可用性问题,等等。

由于 CAP 定理已有严格的证明,本节不去探讨为何 CAP 不可兼得,而是直接分析如果舍弃 C、A、P 时所带来的不同影响。

  • 如果放弃分区容忍性(CA without P),意味着我们将假设节点之间通信永远是可靠的。永远可靠的通信在分布式系统中必定不成立的,这不是你想不想的问题,而是只要用到网络来共享数据,分区现象就会始终存在。在现实中,最容易找到放弃分区容忍性的例子便是传统的关系数据库集群,这样的集群虽然依然采用由网络连接的多个节点来协同工作,但数据却不是通过网络来实现共享的。以 Oracle 的 RAC 集群为例,它的每一个节点均有自己独立的 SGA、重做日志、回滚日志等部件,但各个节点是通过共享存储中的同一份数据文件和控制文件来获取数据的,通过共享磁盘的方式来避免出现网络分区。因而 Oracle RAC 虽然也是由多个实例组成的数据库,但它并不能称作是分布式数据库。
  • 如果放弃可用性(CP without A),意味着我们将假设一旦网络发生分区,节点之间的信息同步时间可以无限制地延长,此时,问题相当于退化到前面“全局事务”中讨论的一个系统使用多个数据源的场景之中,我们可以通过 2PC/3PC 等手段,同时获得分区容忍性和一致性。在现实中,选择放弃可用性的 CP 系统情况一般用于对数据质量要求很高的场合中,除了 DTP 模型的分布式数据库事务外,著名的 HBase 也是属于 CP 系统,以 HBase 集群为例,假如某个 RegionServer 宕机了,这个 RegionServer 持有的所有键值范围都将离线,直到数据恢复过程完成为止,这个过程要消耗的时间是无法预先估计的。
  • 如果放弃一致性(AP without C),意味着我们将假设一旦发生分区,节点之间所提供的数据可能不一致。选择放弃一致性的 AP 系统目前是设计分布式系统的主流选择,因为 P 是分布式网络的天然属性,你再不想要也无法丢弃;而 A 通常是建设分布式的目的,如果可用性随着节点数量增加反而降低的话,很多分布式系统可能就失去了存在的价值,除非银行、证券这些涉及金钱交易的服务,宁可中断也不能出错,否则多数系统是不能容忍节点越多可用性反而越低的。目前大多数 NoSQL 库和支持分布式的缓存框架都是 AP 系统,以 Redis 集群为例,如果某个 Redis 节点出现网络分区,那仍不妨碍各个节点以自己本地存储的数据对外提供缓存服务,但这时有可能出现请求分配到不同节点时返回给客户端的是不一致的数据。

上诉讨论到了CAP在实际使用过程中,如何具体的使用和如何具体的分析,虽然我们一直心心念念的分布式事务最终要保存的“一致性”,但是最终的结论确是**“选择放弃一致性的 AP 系统目前是设计分布式系统的主流选择”**,在分布式环境中“一致性”却不得不成为通常被牺牲,被放弃的那一项属性,但是无论如何,最终确保操作结果在最终交付的时候是正确的,这句话的意思是允许数据在中间过程出错(不一致),但应该在输出时被修正过来。为此,人们又重新给一致性下了定义,将前面我们在 CAP、ACID 中讨论的一致性称为“强一致性”(Strong Consistency),有时也称为“线性一致性”(Linearizability,通常是在讨论共识算法的场景中),而把牺牲了 C 的 AP 系统又要尽可能获得正确的结果的行为称为追求“弱一致性”。不过,如果单纯只说“弱一致性”那其实就是“不保证一致性”的意思……人类语言这东西真的是博大精深。在弱一致性里,人们又总结出了一种稍微强一点的特例,被称为“最终一致性”(Eventual Consistency),它是指:如果数据在一段时间之内没有被另外的操作所更改,那它最终将会达到与强一致性过程相同的结果,有时候面向最终一致性的算法也被称为“乐观复制算法”。

如上,我们讨论的分布式事务中,最开始我们引入各种分布式的处理方式,本意上是追求强一致性,到现在降低成为了“最终一致性”。所以说,在一致性变动的基础上,“事务”这个词的含义我们也同样需要为其进行扩展。我们通常把事务中的ACID称为刚性事务,于是我们在分布式系统中的处理也就可以随之称其为柔性事务,他们包括 可靠事件队列、以及ATTCCSAGAXA 等事务模式,于是也就引出来我们今天的主人公 分布式事务的解决方案者 seata

Seata是什么

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

Seata能够做什么

是一款开源的分布式事务解决方案,能够帮助我们解决前面提及到的分布式事务中出现的问题。具体更多的内容可以去官网查阅相关资料

Seata 安装与启动

Nacos

此处由于我司正常使用都是以Nacos作为配置中心,所以此处也便采用Nacos 作为注册中心,将Seata对应的配置信息注册到Naocs中,最后进行本地启动以及演示操作。

下载与安装

二进制服务下载地址下载地址
在这里插入图片描述

配置数据库信息

进入到如下对应的目录建立对应数据库,创建表(Sql都在对应文件夹中)
在这里插入图片描述
创建完成之后 在application.properties中,填写上对应的数据库连接信息。

启动

晚上以上之后,点击如下启动,进入浏览器即可:
在这里插入图片描述

展示

本机内容地址:8848,用户名和密码都是nacos
在这里插入图片描述

创建

在启动的nacos中,创建一个服务:
在这里插入图片描述
完成之后可以去配置列表中查看自己创建的服务:复制对应的namesapce值:
在这里插入图片描述

Seata服务下载

二进制服务下载地址下载地址

在这里插入图片描述
在以上完成了nacos 的启动之后,下面便可以开始配置Seata相关信息,首先需要注意以下几点

  • 对于Nacos来说 同样需要对应的数据库连接配置,所以需要对应的SQL语句。
  • 需要将配置注册到nacos,所以需要修改注册配置文件。
  • 由于Seata还有自己配置信息,所以还需要修改自己的配置项。
SQL 创建

表结构地址:https://github.com/seata/seata/blob/develop/script/server/db/mysql.sql
新建对应的Seata数据库,创建如下三张表,用于Seata服务。

-- the table to store GlobalSession data
DROP TABLE IF EXISTS `global_table`;
CREATE TABLE `global_table` (
  `xid` VARCHAR(128)  NOT NULL,
  `transaction_id` BIGINT,
  `status` TINYINT NOT NULL,
  `application_id` VARCHAR(32),
  `transaction_service_group` VARCHAR(32),
  `transaction_name` VARCHAR(128),
  `timeout` INT,
  `begin_time` BIGINT,
  `application_data` VARCHAR(2000),
  `gmt_create` DATETIME,
  `gmt_modified` DATETIME,
  PRIMARY KEY (`xid`),
  KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
  KEY `idx_transaction_id` (`transaction_id`)
);

-- the table to store BranchSession data
DROP TABLE IF EXISTS `branch_table`;
CREATE TABLE `branch_table` (
  `branch_id` BIGINT NOT NULL,
  `xid` VARCHAR(128) NOT NULL,
  `transaction_id` BIGINT ,
  `resource_group_id` VARCHAR(32),
  `resource_id` VARCHAR(256) ,
  `lock_key` VARCHAR(128) ,
  `branch_type` VARCHAR(8) ,
  `status` TINYINT,
  `client_id` VARCHAR(64),
  `application_data` VARCHAR(2000),
  `gmt_create` DATETIME,
  `gmt_modified` DATETIME,
  PRIMARY KEY (`branch_id`),
  KEY `idx_xid` (`xid`)
);

-- the table to store lock data
DROP TABLE IF EXISTS `lock_table`;
CREATE TABLE `lock_table` (
  `row_key` VARCHAR(128) NOT NULL,
  `xid` VARCHAR(96),
  `transaction_id` LONG ,
  `branch_id` LONG,
  `resource_id` VARCHAR(256) ,
  `table_name` VARCHAR(32) ,
  `pk` VARCHAR(36) ,
  `gmt_create` DATETIME ,
  `gmt_modified` DATETIME,
  PRIMARY KEY(`row_key`)
);
AT模式下每个业务数据库需要创建undo_log表,用于seata记录分支的回滚信息

表结构地址: https://github.com/seata/seata/blob/1.3.0/script/client/at/db/mysql.sql

-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
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;
修改注册到nacos的配置文件

如下所示可以看到的是,对于我们下载下来的包中,并没有对应的config.txt文档
在这里插入图片描述
我们先行去如下地址config.txt 将对应的信息拷贝下来,然后在于conf同级的目录下创建一个名为config.txt的文件,并将对应的数据拷贝进入,如下图所示:
在这里插入图片描述
同时记得修改对应的配置项信息:如下图所示,修改为自己的数据库用户名和密码
在这里插入图片描述

修改配置信息

进入到conf 目录中,可以看到此文件:
在这里插入图片描述
将其中内容修改为如下,注意自己的用户名和密码

## transaction log store, only used in seata-server
store {
  ## store mode: file、db、redis
  mode = "db"
  ## rsa decryption public key
  publicKey = ""
  ## 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 {
   
    vgroupMapping.my_test_tx_group = "default"
    datasource = "druid"
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://172.16.100.243:3306/seata?rewriteBatchedStatements=true"
    user = "seata"
    password = "123456"
    minConn = 5
    maxConn = 100
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }

  ## redis store property
  redis {
    ## redis mode: single、sentinel
    mode = "single"
    ## single mode property
    single {
      host = "127.0.0.1"
      port = "6379"
    }
    ## sentinel mode property
    sentinel {
      masterName = ""
      ## such as "10.28.235.65:26379,10.28.235.65:26380,10.28.235.65:26381"
      sentinelHosts = ""
    }
    password = ""
    database = "0"
    minConn = 1
    maxConn = 10
    maxTotal = 100
    queryLimit = 100
  }
}

修改注册信息:

进入到conf中,查看如下register.conf配置文件:
在这里插入图片描述
将其内容修改如下:注意对应的namespace填写上在Nacos注册一节中复制到的数值:

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

  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "DEFAULT_GROUP"
    namespace = "3c628611-8dc8-4968-b99e-XXXXXXXX"
    cluster = "default"
    username = ""
    password = ""
  }
  eureka {
    serviceUrl = "http://localhost:8761/eureka"
    application = "default"
    weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = 0
    password = ""
    cluster = "default"
    timeout = 0
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
    aclToken = ""
  }
  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 = "nacos"

  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = "3c628611-8dc8-4968-b99e-XXXXXXXX"
    group = "DEFAULT_GROUP"
    username = ""
    password = ""
    dataId = "seataServer.properties"
  }
  consul {
    serverAddr = "127.0.0.1:8500"
    aclToken = ""
  }
  apollo {
    appId = "seata-server"
    ## apolloConfigService will cover apolloMeta
    apolloMeta = "http://192.168.1.204:8801"
    apolloConfigService = "http://192.168.1.204:8080"
    namespace = "application"
    apolloAccesskeySecret = ""
    cluster = "seata"
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
    nodePath = "/seata/seata.properties"
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.conf"
  }
}
启动

在完成上面配置之后,进入到bin目录下,点击如下启动文件启动
在这里插入图片描述
最终启动结果如下图所示:
在这里插入图片描述

查阅

在完成了 Seata与对应的Nacos的安装和启动之后,可以进入到刚刚创建的Seata服务,查阅对应的信息有没有注册到Nacos上。
如下图所示,可以看到对应的数据已经成功注册。
在这里插入图片描述
并且Seata服务也成功注册到Nacos上,此时意味着Seata已经成功启动并运行。
在这里插入图片描述

测试

到目前位置Seata服务已经能够正确启动,我们就要来检测其是否真的能够实现回滚的效果。

演示

对应的演示源码Seata演示源码
我们可以按照要求依次来启动如下服务

  1. 启动 DubboAccountServiceStarter
  2. 启动 DubboStorageServiceStarter
  3. 启动 DubboOrderServiceStarter
  4. 运行 DubboBusinessTester for demo test

在这里插入图片描述
可以发现先启动三个服务之后,对应的数据库中都会插入对应的值,但是在启动完成 DubboBusinessTester之后,会发现,对应数据库中的值被删除,证明了Seata服务已经能够正常起作用(这里只是在一台数据库中进行模拟整个过程,但是其实现原理还是可以明白的)

后记

本篇文章主要是最近我司要使用分布式事务Seata,让我进行推行,于是就想着现在本地搭建运行,能够大概熟络整个流程,并且对于整体的分布式有一个具体的了解,在后期出现什么问题,也能够找到对应的解决方案。
对于文章中出现的配置也是本人正常运行起来之后贴出来的,所以说算是将网上文章出现的坑都给填平了,对于其中各种配置文件的地址也都给出,若是按照本篇文章进行搭建出现问题,可以私信我,看到必回。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值