分布式事务基础

https://blog.csdn.net/luozhonghua2014/article/details/80037720
1.分布式产生的背景
(1)分库分表,表中数据超过1kw时,单体数据库已无法满足需求,分开后一个操作要同时操作两个库,要保证数据一致,则需要分布式事务
(2)SOA业务代码微服务化,即单机拆成集群,代码重构成分布式的,多库也要符合ACID原则
2.分布式事务的解决方案
(1)基于XA协议的两阶段提交
XA分为两部分,事务管理器和本地资源管理器,本地资源管理器由数据库自己实现,事务管理器作为全局调度者,负责本地资源的统一提交和回滚;事务管理器发出预备和提交命令,本地资源管理器分别响应就绪和成功
缺陷:性能不理想,应用狭隘
在这里插入图片描述

在这里插入图片描述
(2)TCC模式(补偿事务) 最终一致性
i.业务逻辑分为try confirm 和cancel
在这里插入图片描述
ii.TCC各个阶段要做的事情:采用补偿机制,针对每个操作,都注册一个对应的确认和撤销操作,通过第二阶段的补偿机制来实现最终一致性
案例:分布式下转账
1)错误案例
模型一:以下错误案例,一旦转账出错,无法取消,因为try什么都没做,cancel也不能做什么
在这里插入图片描述
模型二:try阶段直接对数据库进行执行的话,即confirm未提交,就进行了写操作,则脏写了;同时别的事务读到了未提交的数据即发生了脏读这种的事务都是错误的,如图:
在这里插入图片描述如果try发生错误,要进行cancel,但是在cancel之前李四转走了卡里的钱,那么cancel就发生了错误了
2)正确操作
模型一:try阶段对张三直接扣款,如果成功了,在confirm对李四进行操作,因为加20的操作不需要锁定资源或者检查什么,cancel的话也是只用对张三换20元即可,这个模型是正确的
在这里插入图片描述

模型二:标准的TCC编程模型,try阶段仍然只锁定资源,具体操作交给confirm
在这里插入图片描述
ps:以上模型一更高效,模型二更标准,因为模型一在confirm对张三的操作比模型二少了一次db操作
在这里插入图片描述
try:完成所有业务检查,预留必须的业务资源如扣钱业务,必须锁定要扣的20元,否则防止并发检查时是有20的,但是执行扣除的时候其他线程先扣没了;核心原则:try阶段决定分布式事务是否成功,即判断成功的标志如:检查库存是否足够,转账时卡里钱是否足够,不够的话即失败
confirm:不检查任何业务,只使用try预留的业务资源,处理try阶段冻结的业务;核心原则,try阶段成功,confirm必须陈宫,confirm也是补偿阶段;
cancel:回滚业务,释放资源 恢复try操作;核心原则,只要try失败cancel必须成功,cancel也是补偿阶段
TCC是将一个大的事务分成两阶段的多个子事务,第一和第二阶段事务独立,即两个阶段的时候可以异步执行
TCC成功执行图解
在这里插入图片描述TCC失败执行图解:
23
补偿:就是当confirm执行第一次不成功时,要有能够再次执行的机制,即定时任务;定时任务固定频率的补偿是主动补偿;主动补偿后需要将失败的事务记录下来,进行人工干预,即人工补偿;即TCC在异常时,会出现最终不一致的情况,需要有人工补偿机制
hmily开源框架 TCC
人为代码实现两阶段提交,不同场景复杂度不同,不能被复用
iii.所有的分布式事务解决方案都要有补偿机制,都属于最终一致性
iv.tcc需要创建tcc数据库保存事务日志,用于后续的人工干预
(3)消息事务和最终一致性:变种两阶段提交
MQ事务消息,基于消息中间件的分布式事务
3.分布式事务管理需要
(1)应用程序,全局事务管理器,数据源,相当于将单机的本地事务管理器拿出来
(2)事务管理器协调数据源,两者需要通信,需要一套协议规范
(3)应对网络主机等故障时,事务管理器和数据源需要记录相关的事务日志
4.分布式事务协议
(1)XA规范,是一种接口规范,各个数据库厂商提供实现;weblogic和websfere提供JTA实现和支持,但tomcat没有,需要借助jotm和automikos等第三方框架实现,支持spring整合
(2)两阶段提交协议2PC
5.分布式系统的一致性保障
(1)CAP理论
C:一致性,即分布式系统中所有数据备份,在同一时刻拥有相同的值,即所有节点访问同一份最新的数据副本
P:分区容错性,分区容错意味着除了彻底失效以外,发生任何故障时,系统都能够正常运行。也就是说,如果网络中的某个节点发生了故障,系统的其余部分必须适应并填补发生故障的部分
A:在集群一部分节点故障后,系统还能否对对读写请求做成响应
CAP无法同时满足的原因举例
假设 DB服务搭建在两地X 和Y,同时提供读写服务:
i.如果X和Y都写成功DB才返回成功
在无网络故障的前提下,满足C和A,即一致性和可用性,因为一旦成功,两地的数据一定是一致的,同时读写都成功了,满足可用性,但是不满足P,因为一旦网络故障出现,X或者Y之一无法成功,则整体失败,即分区容错为0;
ii.如果DB服务只在本地库写成功,另一个通过其他方式同步
除非完全的网络故障,否则也可以提供服务,但X和Y 的数据并非在同一时刻都一样,只是最终一致而已,即满足C和P,但不满足A
iii如果DB在网络故障时提供降级服务
降级服务,如网络故障时只提供读服务,不提供写服务,则C和P满足,而对于A可用性,则无法满足
一般情况下都是牺牲了C一致性,满足可用和分区容错性的,可用性是因为对用户来说,系统不可用是不能忍的,分区容错性是因为网络不可信这个客观事实,只能牺牲一致性,从而追求最终一致性
(2)BASE理论
i.出现的原因:CAP理论只能二选一
ii.概念:
Basically Available(基本可用),soft state软状态,Eventually consistent 最终一致性
基本可用常见情况:
响应时间上的损失,功能上的降级;
软状态:即允许各个节点的数据存在中间状态,这些中间状态可能并不相同,但是不影响整体可用性,只追求最终一致性
最终一致性:
系统在数据写入成功之后,不承诺立即可以读到最新写入的值,也不会具体的承诺多久之后可以读到。但会尽可能保证在某个时间级别(比如秒级别)之后,可以让数据达到一致性状态。
6.两阶段提交分布式事务落地框架lcn与springcloud结合
(1)创建数据库和数据表:用于异常信息的回滚
创建MySQL数据库, 名称为: tx-manager

CREATE TABLE `t_tx_exception`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `group_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `mod_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `transaction_state` tinyint(4) NULL DEFAULT NULL,
  `registrar` tinyint(4) NULL DEFAULT NULL,
  `remark` varchar(4096) NULL DEFAULT  NULL,
  `ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 未解决 1已解决',
  `create_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

(2)搭建tx-lcn的TM端:
i.通过git拉下来整个代码仓库

git clone https://github.com/codingapi/tx-lcn.git & cd txlcn-tm
cd txlcn-tm
mvn clean  package '-Dmaven.test.skip=true'

ii.将其中的tm拿出来到自己的项目中,直接maven导入即可
在这里插入图片描述
iii.修改tm端的配置文件

spring.application.name=tx-manager
server.port=7970
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=root

mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true

#tx-lcn.logger.enabled=true
# TxManager Host Ip
#tx-lcn.manager.host=127.0.0.1
# TxClient连接请求端口,默认端口就是8070
#tx-lcn.manager.port=8070
# 心跳检测时间(ms)
#tx-lcn.manager.heart-time=15000
# 分布式事务执行总时间
#tx-lcn.manager.dtx-time=30000
#参数延迟删除时间单位ms
#tx-lcn.message.netty.attr-delay-time=10000
#tx-lcn.manager.concurrent-level=128
# 开启日志
#tx-lcn.logger.enabled=true
#logging.level.com.codingapi=debug
#redis 主机
#spring.redis.host=127.0.0.1
#redis 端口
#spring.redis.port=6379
#redis 密码
#spring.redis.password=

iv.直接启动tm端下的TMApplication主类
v.访问localhost:7970,然后输入密码codingapi,登录即可
在这里插入图片描述
vi.开启本地redis服务
(3)tc端,分布式事务客户端的搭建:
i.所有的tc端引入jar包:

 <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>

ii.tc端主类上使用:@EnableDistributedTransaction
iii业务方法调用上使用; @LcnTransaction //分布式事务注解

  @LcnTransaction//分布式事务
    //@Transactional //本地事务
    @Override
    public String gathering(String accountNumberFrom,String accountNumberTo, String money) {

        //加钱
        logger.info("---------------开始调用加钱服务----------");
        this.doGathering(accountNumberTo,new BigDecimal(money));
        logger.info("---------------加钱服务调用结束-----------");
        //转钱
        logger.info("------开始调用转账服务---------");
        String resultT = iFeignService.transfer(accountNumberFrom,money);
        logger.info("---------------转账服务调用结束--------");
        return "execute result :"+ resultT;
    }

iv.tc配置文件中加上tm端的端口:

# 以下是默认配置
tx-lcn.client.manager-address=127.0.0.1:8070 

(4)客户端调用
http://localhost:8081/gatheringController/feign/123/321/120

  @RequestMapping("/feign/{accountNumberFrom}/{accountNumberTo}/{money}")
    public String getFeignService(@PathVariable String accountNumberFrom,@PathVariable String accountNumberTo,@PathVariable String money){
        return  iService.gathering(accountNumberFrom,accountNumberTo,money);
    }

(5)参考官网: https://www.txlcn.org/zh-cn/docs/demo/env.html
(6)lcn分布式事务的调用过程
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值