分布式事务存在的原因:数据分布在不同的数据库实例。一个分布式系统下存在多个模块协调来完成一次业务,每一个模块对应一个数据源,同一个业务需要操作不同的模块,改动不同的数据库,要么都成功,要么都失败。
举例:
去A库中存储老师实体类的数据
?1234567@Datapublic class Teacher{ @Id private Integer tid; @Field private String tname;}
去B库中存储学生实体类的数据
?12345678910@Data@Documentpublic class Teacher{ @Id private String id; @Field privtae String name; @Field private Integer tid;}
这两个pojo类通过tid关联,学生对老师是一对多的关系,两个POJO的数据通过mysql存储在两个不同的类。
常见的分布式框架解决方案
全局事务2pc --关系型数据库
缺点:效率低,算法执行过程中,所有的节点处于阻塞状态,所有节点所持有的资源处于封锁状态。
3pc(三段提交协议)
消息中间件
提供回滚接口
为了方便我们了解分布式事务框架,我们需要先了解的相关说明。
Spring本地事务是在同一个系统里做的实务操作,需要符合数据库事务ACID特性,为刚性事务;而分布式事务往往不能满足ACID,不同的数据库实例对同一个方法在一个时间的响应并不完全一样,但可能最终一致,这种事务是柔性事务。
柔性事务定理了解
1. CAP定理
一个分布式系统于事务由三个特性:Consistency(一致性) 、Availability(可用性)、 Partition tolerance(分区容错性)。现实情况下,分布式系统最多同时满足其中两个,不能同时满足三个。
可用性和一致性是矛盾的,原因是在分布式事务中操作多个节点的时候,一个节点坏了还得有别的节点来承担,这是为了满足可用性,但不符合一致性。
分区容错性意思是,系统不能在一定时限内达到数据的一致性,就意味着发生了分区的情况。假设在一定时间内,A节点和C节点没能同步数据,那么框架需要决定到底是A版本还是C版本作为后续操作数据的基版。
2. BASE理论
CAP理论的优化。Basically Available(基本可用 )、soft state(软状态),Eventually consistent(最终一致性)三个短语的缩写。
BASE理论要求,即使无法做到节点强一致,但每个分布式应用都可以根据自身业务特点,采用适当的方式达到最终一致性。
BA基本可用:指分布式系统中出现不可知故障的时候,允许损失部分可用性,但不代表整个系统不可用。(比如秒杀活动的并发降级页面)
S软状态:系统中数据允许存在中间状态(软状态),并认为这个状态不影响可用性,允许分布式节点之间存在同步延迟。(如Eureka集群同步数据)
最终一致性:允许整个系统数据在经过一定时间后,最终能达到整个系统的一致性。为弱一致性,响应给用户结果时整个系统没有达到一致性,但最终一定会达到一致性的。
强一致性:系统接受请求后,整个系统必须达到一致的结果才能响应。
根据不同的解决方案衍生出了不同的分布式事务技术,下面介绍不同的分布式技术在这个示例的表现。
LCN
介绍
XA两阶段提交协议
第一阶段所有的参与者TC(Transaction Client)准备执行事务并锁住需要的资源,并向事务管理器报备自己已经准备好。
第二阶段事务管理器负责协调,向不同的RM(资源管理器)索要数据,尽可能晚提交事务(在提交之前完成所有的工作),但也要等待TM(Transaction Manager)响应容易阻塞。吞吐量优先,不适合互联网。
三种模式
基于XA两阶段提交协议,现存LCN分布式事务框架有三种模式,分别是LCN模式,TCC模式,TXC模式。
1. LCN模式:基于jdbc关系型数据库实现对本地事务的操作,然后在由TM(Transaction Manager)统一协调控制事务。当本地事务提交回滚或者关闭连接时将会执行假操作,该代理的连接将由LCN连接池管理。基于注解 @LcnTransaction。
2. TCC模式:基于非关系型数据库(非关系型就是非事务性,除此之外也支持关系型数据库),相对于传统事务机制(X/Open XA Two-Phase-Commit),其特征在于它不依赖资源管理器(RM)对XA的支持,而是通过对(由业务系统提供的)业务逻辑的调度来实现分布式事务。主要由三阶段完成,Try: 尝试执行业务、 Confirm:确认执行业务、 Cancel: 取消执行业务。特点:完全依赖开发者,通过重写三个方法来实现对事务的控制,基于注解@TccTransaction。
3. TXC模式:命名来源于淘宝,实现原理是在执行SQL之前,先查询SQL的影响数据,然后保存执行的SQL快走信息和创建锁。当需要回滚的时候就采用这些记录数据回滚数据库,目前锁实现依赖redis分布式锁控制。特点:嵌入低,不会占用数据库的连接资源,资源消耗较多,基于注解@TxcTransaction。
LCN原理解析
事务发起方和参与方都属于TxClient,TxManager负责控制整个事务。
123代表三个txClient将自己的事务发布到TxManager,4为发起方告诉txManager获取数据成功或者失败,如果成功(其中一个失败也算失败),TxManager返回通知AB让他们各自提交自己的事务。5为txManager通知发起方提交自己的事务。
LCN事务核心步骤
1. 创建事务组:事务发起方在开始执行业务代码之前先调用txManager创建事务组对象,拿到事务表示GroupId。
2. 加入事务组:2和3,参与方将自己的事务执行情况报备给txManager
3. 通知事务组:发起方执行完业务代码之后,将执行结果状态通知给txManager
4. 通知事务单元:txManager询问参与方的事务执行结果
5. 响应通知事务组:txManager通知发起方事务的最终结果
配置Tx-LCN案例
一、新建
1. 执行依赖中带有的tx-manager.sql文件到数据库中
2. 配置application.properties
TC配置
# 是否启动LCN负载均衡策略(优化选项,开启与否,功能不受影响)
tx-lcn.ribbon.loadbalancer.dtx.enabled=true
# tx-manager 的配置地址,可以指定TM集群中的任何一个或多个地址
# tx-manager 下集群策略,每个TC都会从始至终[/span>断线重连
# TM方,每有TM进入集群,会找到所有TC并通知其与新TM建立连接。
# TC方,启动时按配置与集群建立连接,成功后,会再与集群协商,查询集群大小并保持与所有TM的连接
tx-lcn.client.manager-address=127.0.0.1:8070
# 该参数是分布式事务框架存储的业务切面信息。采用的是h2数据库。绝对路径。该参数默认的值为{user.dir}/.txlcn/{application.name}-{application.port}
tx-lcn.aspect.log.file-path=logs/.txlcn/demo-8080
# 调用链长度等级,默认值为3(优化选项。系统中每个请求大致调用链平均长度,估算值。)
tx-lcn.client.chain-level=3
# 该参数为tc与tm通讯时的最大超时时间,单位ms。该参数不需要配置会在连接初始化时由tm返回。
tx-lcn.client.tm-rpc-timeout=2000
# 该参数为分布式事务的最大时间,单位ms。该参数不允许TC方配置,会在连接初始化时由tm返回。
tx-lcn.client.dtx-time=8000
# 该参数为雪花算法的机器编号,所有TC不能相同。该参数不允许配置,会在连接初始化时由tm返回。
tx-lcn.client.machine-id=1
# 该参数为事务方法注解切面的orderNumber,默认值为0.
tx-lcn.client.dtx-aspect-order=0
# 该参数为事务连接资源方法切面的orderNumber,默认值为0.
tx-lcn.client.resource-order=0
# 是否开启日志记录。当开启以后需要配置对应logger的数据库连接配置信息。
tx-lcn.logger.enabled=false
tx-lcn.logger.driver-class-name=${spring.datasource.driver-class-name}
tx-lcn.logger.jdbc-url=${spring.datasource.url} #jdbc:mysql://localhost:3306/tx-manager?characterEncoding=UTF-8 遇上servertimezone问题添加serverTimezone=GMT
tx-lcn.logger.username=${spring.datasource.username}
tx-lcn.logger.password=${spring.datasource.password}
tx-lcn.logger.enabled=false #如果打开事务:更改 tx-lcn.logger.enabled=true
TM配置
spring.application.name=TransactionManager
server.port=7970
# JDBC 数据库配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tx-manager?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
# 数据库方言
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
# 第一次运行可以设置为: create, 为TM创建持久化数据库表
spring.jpa.hibernate.ddl-auto=validate
# TM监听IP. 默认为 127.0.0.1
tx-lcn.manager.host=127.0.0.1
# TM监听Socket端口. 默认为 ${server.port} - 100
tx-lcn.manager.port=8070
# 心跳检测时间(ms). 默认为 300000
tx-lcn.manager.heart-time=300000
# 分布式事务执行总时间(ms). 默认为36000
tx-lcn.manager.dtx-time=8000
# 参数延迟删除时间单位ms 默认为dtx-time值
tx-lcn.message.netty.attr-delay-time=${tx-lcn.manager.dtx-time}
# 事务处理并发等级. 默认为机器逻辑核心数5倍
tx-lcn.manager.concurrent-level=160
# TM后台登陆密码,默认值为codingapi
tx-lcn.manager.admin-key=codingapi
# 分布式事务锁超时时间 默认为-1,当-1时会用tx-lcn.manager.dtx-time的时间
tx-lcn.manager.dtx-lock-time=${tx-lcn.manager.dtx-time}
# 雪花算法的sequence位长度,默认为12位.
tx-lcn.manager.seq-len=12
# 异常回调开关。开启时请制定ex-url
tx-lcn.manager.ex-url-enabled=false
# 事务异常通知(任何http协议地址。未指定协议时,为TM提供内置功能接口)。默认是邮件通知
tx-lcn.manager.ex-url=/provider/email-to/**@.com
# 开启日志,默认为false
tx-lcn.logger.enabled=true
tx-lcn.logger.enabled=false
tx-lcn.logger.driver-class-name=${spring.datasource.driver-class-name}
tx-lcn.logger.jdbc-url=${spring.datasource.url}
tx-lcn.logger.username=${spring.datasource.username}
tx-lcn.logger.password=${spring.datasource.password}
# redis 的设置信息. 线上请用Redis Cluster
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
配置本地事务和分布式事务
@Configuration
@EnableTransactionManagement
public class TransactionConfiguration {
/
本地事务配置
@param transactionManager
@return
/
@Bean
@ConditionalOnMissingBean
public TransactionInterceptor transactionInterceptor(PlatformTransactionManager transactionManager) {
Properties properties = new Properties();
properties.setProperty("", "PROPAGATION_REQUIRED,-Throwable");
TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
transactionInterceptor.setTransactionManager(transactionManager);
transactionInterceptor.setTransactionAttributes(properties);
return transactionInterceptor;
}
/**
分布式事务配置 设置为LCN模式
@param dtxLogicWeaver
@return
/
@ConditionalOnBean(DTXLogicWeaver.class)
@Bean
public TxLcnInterceptor txLcnInterceptor(DTXLogicWeaver dtxLogicWeaver) {
TxLcnInterceptor txLcnInterceptor = new TxLcnInterceptor(dtxLogicWeaver);
Properties properties = new Properties();
properties.setProperty(Transactions.DTX_TYPE,Transactions.LCN);
properties.setProperty(Transactions.DTX_PROPAGATION, "REQUIRED");
txLcnInterceptor.setTransactionAttributes(properties);
return txLcnInterceptor;
}
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
//需要调整优先级,分布式事务在前,本地事务在后。
beanNameAutoProxyCreator.setInterceptorNames("txLcnInterceptor","transactionInterceptor");
beanNameAutoProxyCreator.setBeanNames("Impl");
return beanNameAutoProxyCreator;
}
}
二、依赖
TX-Manager配置,独立于微服务,是独立的依赖
[/span>dependencies
[/span>dependency
[/span>groupId
[/span>artifactId
[/span>dependency
[/span>groupId
[/span>artifactId
[/span>dependency
[/span>groupId
[/span>artifactId
[/span>scope
[/span>dependency
[/span>groupId
[/span>artifactId
[/span>version
[/span>dependencyManagement
[/span>dependencies
[/span>dependency