您的位置:首页 > 编程语言 > Java开发

spring cloud: TX-LCN解决分布式事务

2019-08-13 17:31 429 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/SuperBins/article/details/99438794

分布式事务预备知识

1、本地事务的ACID
A:原子性(Atomicity) 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。
事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
C:一致性(Consistency) 事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。
如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。
I:隔离性(Isolation) 指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
d:持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
2、分布式事务基础
CAP : CAP定理,又被叫作布鲁尔定理。对于设计分布式系统来说(不仅仅是分布式事务)的架构师来说,CAP就是你的入门理论。
C (一致性):对某个指定的客户端来说,读操作能返回最新的写操作。对于数据分布在不同节点上的数据上来说,如果在某个节
点更新了数据,那么在其他节点如果都能读取到这个最新的数据,那么就称为强一致,如果有某个节点没有读取到,那就是分
布式不一致。
A (可用性):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。可用性的两个关键一个是合理的时间,
一个是合理的响应。合理的时间指的是请求不能无限被阻塞,应该在合理的时间给出返回。合理的响应指的是系统应该明确返回
结果并且结果是正确的,这里的正确指的是比如应该返回50,而不是返回40。
P (分区容错性):当出现网络分区后,系统能够继续工作。打个比方,这里个集群有多台机器,有台机器网络出现了问题,
但是这个集群仍然可以正常工作。

BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。是对CAP中AP的一个扩展

基本可用:分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。
软状态:允许系统中存在中间状态,这个状态不影响系统可用性,这里指的是CAP中的不一致。
最终一致:最终一致是指经过一段时间后,所有节点数据都将会达到一致。
3、分布式解决方案
一、2PC
说到2pc就不得不聊聊数据库分布式事务中的XA transactions
在XA协议中分为两阶段:
第一阶段:事务管理器要求每个涉及到事务的数据库预提交(precommit)此操作,并反映是否可以提交.
第二阶段:事务协调器要求每个数据库提交数据,或者回滚数据。
优点: 尽量保证了数据的强一致,实现成本较低,在各大主流数据库都有自己实现,对于MySQL是从5.5开始支持。
缺点:
单点问题:事务管理器在整个流程中扮演的角色很关键,如果其宕机,比如在第一阶段已经完成,在第二阶段正准备提交的时候事务管理器宕机,资源管理器就会一直阻塞,导致数据库无法使用。
同步阻塞:在准备就绪之后,资源管理器中的资源一直处于阻塞,直到提交完成,释放资源。
数据不一致:两阶段提交协议虽然为分布式数据强一致性所设计,但仍然存在数据不一致性的可能,比如在第二阶段中,假设协调者发出了事务commit的通知,但是因为网络问题该通知仅被一部分参与者所收到并执行了commit操作,其余的参与者则因为没有收到通知一直处于阻塞状态,这时候就产生了数据的不一致性。

二、TCC
对于TCC的解释:
Try阶段:尝试执行,完成所有业务检查(一致性),预留必须业务资源(准隔离性)
Confirm阶段:确认执行真正执行业务,不作任何业务检查,只使用Try阶段预留的业务资源,Confirm操作满足幂等性。要求具备幂等设计,Confirm失败后需要进行重试。
Cancel阶段:取消执行,释放Try阶段预留的业务资源
Cancel操作满足幂等性Cancel阶段的异常和Confirm阶段异常处理方案基本上一致。

对于TCC来说适合一些:

强隔离性,严格一致性要求的活动业务。
执行时间较短的业务

三、本地消息表
此方案的核心是将需要分布式处理的任务通过消息日志的方式来异步执行。消息日志可以存储到本地文本、数据库或消息队列,再通过业务规则自动或人工发起重试。人工重试更多的是应用于支付场景,通过对账系统对事后问题的处理。
本地消息队列是BASE理论,是最终一致模型,适用于对一致性要求不高的。

四、可以通过MQ + zookeeper实现分布式事务

五、使用框架TX-LCN(我们不生产水,我们只是大自然的搬运工!)
其实tx-lcn的核心是通过2PC + TCC补偿机制,采用强一致性方案,保证了事务的一致性。因此说是一个解决方案,不如说是2PC + TCC方式的一个实现框架。
TX-LCN的核心:
创建事务组: 是指在事务发起方开始执行业务代码之前先调用TxManager创建事务组对象,然后拿到事务标示GroupId的过程。

添加事务组: 添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息添加通知给TxManager的操作。

关闭事务组: 是指在发起方执行完业务代码以后,将发起方执行结果状态通知给TxManager的动作。当执行完关闭事务组的方法以后,TxManager将根据事务组信息来通知相应的参与模块提交或回滚事务。

开始搭建项目:

本服务采用tx-lcn 5.0.2.RELEASE版本。
1、搭建TxManager
TxManager是LCN分布式事务框架的事务协调器,框架基于Netty做消息通讯,事务控制数据存储在redis中。TxManager采用高可用集群化部署方案,多个TM通过eureka集群完成服务注册,各个TxClient通过服务名称向TxManager发送事务信息。
引入相关依赖

<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tm</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>


配置文件:

#应用名称
spring.application.name=tx-manager
server.port=7970
#DataSource配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/bins?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=bins123
#redis 配置
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=

#注册中心地址
eureka.client.serviceUrl.defaultZone= http://localhost:10025/eureka/
# 注册名
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
# 设置注册到服务的为ip
eureka.instance.prefer-ip-address=true
#开启驼峰
mybatis.configuration.map-underscore-to-camel-case=true
#允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。  default:false
mybatis.configuration.use-generated-keys=true

# tx-manager ip(client请求ip)
tx-lcn.manager.host=127.0.0.1
# client 请求端口
tx-lcn.manager.port=8070
# 心跳检测时间 单位:ms
tx-lcn.manager.heart-time=12000
# 事务执行总时间
tx-lcn.manager.dtx-time=3000
# 参数延迟删除时间单位ms
tx-lcn.message.netty.attr-delay-time=4000
tx-lcn.manager.concurrent-level=128
# 开启日志
tx-lcn.logger.enabled=true
logging.level.com.codingapi=debug

搭建好之后运行我们的txmanager服务。
访问 http://127.0.0.1:7970/admin 密码默认为codingapi

搭建tx-client
TxClient的代理连接池实现了javax.sql.DataSource接口,并重写了close方法,事务模块提交关闭以后,TxClient连接池执行“假关闭”操作,等待TxManager协调完成事务以后在关闭连接。
加入相关依赖

<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-txmsg-netty</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>

启动类添加 @EnableDistributedTransaction。
当然需要添加两个服务我们命名为A、B关系(A调用B)
A中需要事务的地方添加
@LcnTransaction(分布式事务)
@Transactional(本地事务)
在B中需要事务的地方添加
@LcnTransaction
@Transactional
启动A、B则可以在TX-MANAGER的系统后台看到相关信息

至此:项目配置完毕!

分布式事务时间,这个点非常重要,此时间要和网关的时间做一个统一协调,要不容易出问题!
(今天就写到这里啦!)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: