springCloud+eureka分布式事务详解

springcloud+eureka的分布式事务处理,记录LCN和SEATA两种处理方案

分布式事务

分布式事务是指事务的参与者,支持事务的服务器,资源服务器分别位于分布式系统的不同节点之上,通常一个分布式事物中会涉及到对多个数据源或业务系统的操作。 例如:跨银行转操作就涉及调用两个异地银行服务

CAP理论
CAP理论:一个分布式系统不可能同时满足一致性,可用性和分区容错性 三个基本需求,最多只能同时满足其中两项
一致性consistency:数据在多个副本之间是否能够保持一致的特性。
可用性availability:是指系统提供的服务必须一致处于可用状态,对于每一个用户的请求总是在有限的时间内返回结果,超过时间就认为系统是不可用的
分区容错性Partition Tolerance:分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务,除非整个网络环境都发生故障。

CAP定理的应用
放弃P(CA):如果希望能够避免系统出现分区容错性问题,一种较为简单的做法就是将所有的数据(或者是与事物相关的部分数据)都放在一个分布式节点上,这样虽然无法保证100%系统不会出错,但至少不会碰到由于网络分区带来的负面影响
放弃A(CP): 一旦系统遇到网络分区或其他故障时,那受到影响的服务需要等待一定的时间,应用等待期间系统无法对外提供正常的服务,即不可用
放弃C(AP): 并非完全不需要数据一致性,是指放弃数据的强一致性,保留数据的最终一致性。

BASE理论
BASE: 基本可用Basic available,软状态soft state,最终一致性Eventual Consistency。是对CAP中一致性和可用性权限的结果,是基于CAP定理演化而来的,核心思想是即使无法做到强一致性,但每个应用都可以根据自身的业务特定,采用适当的方式来使系统达到最终一致性

2PC提交
二阶段提交协议是将事务的提交过程分成提交事务请求和执行事务提交两个阶段进行处理。
阶段1:提交事务请求
事务询问:协调者向所有的参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待各参与者的响应
执行事务:各参与者节点执行事务操作,并将Undo和Redo信息记入事务日志中
如果参与者成功执事务操作,就反馈给协调者Yes响应,表示事物可以执行,如果没有成功执行事务,就反馈给协调者No响应,表示事务不可以执行
二阶段提交的阶段也被称为投票阶段,即各参与者投票票表明是否可以继续执行接下去的事务提交操作

阶段二:执行事务提交
1、假如协调者从所有的参与者或得反馈都是Yes响应,那么就会执行事务提交。
2、发送提交请求:协调者向所有参与者节点发出Commit请求
3、事务提交:参与者接受到Commit请求后,会正式执行事务提交操作,并在完成提交之后放弃整个事务执行期间占用的事务资源
4、反馈事务提交结果:参与者在完成事物提交之后,向协调者发送ACK消息
5、完成事务:协调者接收到所有参与者反馈的ACK消息后,完成事务
最后中断事务,事务结束

假如任何一个参与者向协调者反馈了No响应,或者在等待超市之后,协调者尚无法接收到所有参与者的反馈响应,那么就中断事务。
发送回滚请求:协调者向所有参与者节点发出Rollback请求
事务回滚:参与者接收到Rollback请求后,会利用其在阶段一种记录的Undo信息执行事物回滚操作,并在完成回滚之后释放事务执行期间占用的资源。
反馈事务回滚结果:参与则在完成事务回滚之后,向协调者发送ACK消息
中断事务:协调者接收到所有参与者反馈的ACk消息后,完成事务中断、事务结束
优缺点
原理简单,实现方便
缺点是同步阻塞,单点问题,脑裂,保守

3PC提交
三阶段提,也叫三阶段提交协议,是二阶段提交(2PC)的改进版本。
与两阶段提交不同的是,三阶段提交有两个改动点。引入超时机制。同时在协调者和参与者中都引入超时机制。在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。
三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。

springcloud搭建省略

第一种、SEATA

seata的设计思想
Seata的设计目标其一是对业务无侵入,因此从业务无侵入的2PC方案着手,在传统2PC的基础上演进,并解决2PC方案面临的问题。
Seata把一个分布式事务理解成一个包含了若干分支事务的全局事务。全局事务的职责是协调其下管辖的分支事务达成一致,要么一起成功提交,要么一起失败回滚。
引用几张网上扒的图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
seata的3个组件
Transaction Coordinator (TC): 事务协调器,它是独立的中间件,需要独立部署运行,它维护全局事务的运行状态,接收TM指令发起全局事务的提交与回滚,负责与RM通信协调各各分支事务的提交或回滚。
Transaction Manager TM: 事务管理器,TM需要嵌入应用程序中工作,它负责开启一个全局事务,并最终向TC发起全局提交或全局回滚的指令。
Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报,并接收事务协调器TC的指令,驱动分支(本地)事务的提交和回滚。
TC是单独的服务,TM和RM是以jar包的形式嵌入
seata执行流程
1、每个RM使用DataSourceProxy连接数据库,其目的是使用ConnectionProxy,使用数据源和数据连接代理的目的就是在第一阶段将undo_log和业务数据放在一个本地事务提交,这样就保存了只要有业务操作就一定有undo_log。
2、在第一阶段undo_log中存放了数据修改前和修改后的值,为事务回滚作好准备,所以第一阶段完成就已经将分支事务提交,也就释放了锁资源。
3、TM开启全局事务开始,将XID全局事务id放在事务上下文中,通过feign调用也将XID传入下游分支事务,每个分支事务将自己的Branch ID分支事务ID与XID关联。
4、第二阶段全局事务提交,TC会通知各各分支参与者提交分支事务,在第一阶段就已经提交了分支事务,这里各个参与者只需要删除undo_log即可,并且可以异步执行,第二阶段很快可以完成。
5、第二阶段全局事务回滚,TC会通知各各分支参与者回滚分支事务,通过 XID 和 Branch ID 找到相应的回滚日志,通过回滚日志生成反向的 SQL 并执行,以完成分支事务回滚到之前的状态,如果回滚失败则会重试回滚操作。
整合部署
1、下载seata-server包,并解压
seata下载链接:github网址
2、修改conf目录下的file.conf、 registry.conf两个配置文件

## transaction log store, only used in seata-server
store {
   
  ## store mode: file、db、redis
  mode = "db"   采用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)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    ##url = "jdbc:mysql://127.0.0.1:3306/seata"
    url = "jdbc:mysql://IP:3306/tends_testdb"
    user = "root"
    password = "密码"
    minConn = 5
    maxConn = 30
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }

  ## redis store property
  redis {
   
    host = "127.0.0.1"
    port = "6380"
    password = ""
    database = "0"
    minConn = 1
    maxConn = 10
    queryLimit = 100
  }

}
registry {
   
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "eureka"    采用eureka模式

  nacos {
   
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = ""
    password = ""
  }
  eureka {
   
    serviceUrl = "http://172.17.133.233:9000/eureka,http://172.17.133.233:9001/eureka"
    application = "seata-server"
    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"
  }
  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 = "127.0.0.1:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = ""
    password = ""
  }
  consul {
   
    serverAddr = "127.0.0.1:8500"
  }
  apollo {
   
    appId = "seata-server"
    apolloMeta = "http://192.168.1.204:8801"
    namespace = "application"
  }
  zk {
   
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
  }
  etcd3 {
   
    serverAddr = "http://localhost:2379"
  }
  file {
   
    name = "file.conf"
  }
}

3、mysql执行sql

-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128<
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值