分布式事务的认识

简介: 分布式系统处理业务时,经常需要调用不同的应用处理业务,为保证数据正确性,需要保证调用的各应用保证业务处理同时成功,或某个应用处理业务失败时同时回滚,即保证分布式的事务。

1.分布式事务介绍

1.事务与分布式事务

一般事务包含四个特点:ACID

Atomicity(原子性):事务作为整体不可分割,要么执行,要么不执行,不能有部分执行。

Consistency(一致性):事务从执行开始到执行结束,保证数据的完整性约束不被破坏。

Isolation(隔离性):事务之间的执行应该互不影响。

Durability(持久性):事务已完成的数据修改因保存进数据库,不再修改。

对于单应用,事务的实现直接用数据库的事务即可解决。而对于分布式的事务(包括单应用多数据库和多应用的情况),必须保证多个数据库或应用的事务同时执行或回滚。


2PC、3PC、TCC

2PC是包括准备阶段(prepare)和提交阶段(commit),即第一阶段让所用的应用进入数据准备阶段,可以理解为执行sql但不提交,接着执行第二阶段让所有的应用都提交sql。这一过程中需要一个全局角色(协调者)来通知每个应用该进入哪一阶段。

以消费业务为例,一个消费请求需要访问订单中心生成订单,访问库存中心扣减库存,当接受到一个消费请求时,需要由协调者通知订单生成订单,通知库存扣减库存,若两个应用都成功完成准备阶段并已通知协调者,则协调者再分别通知订单与库存提交事务,若都成功执行则事务完成。若准备阶段中其中一个执行失败,则由协调则通知另一个进行回滚。

缺点:

2PC依赖协调者,若出现网络问题,一部分导致一部分无法提交,则会锁住资源阻塞其他参与者,若协调者宕机,参与者都处于锁定资源无法提交事务的状态,出现网络问题都会一直重试直到参与者都提交或回滚成功,最后可能需要人工介入处理。


3PC包括CanCommit、PreCommit、DoCommit三个阶段,相比于2PC多了一个步骤,用于询问参与者是否能够提交(参与者检查的数据是否能进行更新,并不会锁定资源),来保证参与者在数据提交阶段状态一致,3PC引入了超时处理,如果等待提交命令超时,则参与者会提交事务,然而超时问题依然存在

缺点:对于等待提交命令超时时,参与者默认会直接提交数据,然而协调者可能发来的是回滚命令,可能导致数据不一致。相比于2PC多了一个数据准备阶段,使交互时间更长,性能有所下降,且依然有数据不一致的问题。


TCC(try-confirm-cancel)又叫做补偿事务,事务失败时,需要做相反的操作使数据还原(cancel),因此对于每个操作都要一个confirm操作和cancel操作用于事务确认和回滚,TCC的三个阶段分别为:

try阶段用于对数据检测(一致性)和资源预留(隔离性)。

confirm用于执行业务,只使用try阶段预留的资源,一般try阶段成功,confirm阶段也会成功。

cancel用于处理业务失败,要对业务失败进行回滚,并释放try阶段预留的资源。


最终一致性:

TCC事务的执行过程中,因为没有锁定数据,可能有其他事务进行数据修改(未提交读),导致数据一致性遭到破坏,但在所有参与者都执行完confirm或cancel之后数据最终会回到一致状态,极为最终一致性。而2PC或3PC,都是强一致性的分布式事务,在执行事务过程中都会锁定资源,其他事务无法访问,直到参与者全部提交或回滚。最终一致性不会锁定资源,因此可以得到较大的数据吞吐量。


2.业务处理中的事务解决方式

1.利用RPC框架的异常

rpc框架的异常都是可以抛出到服务调用端的,根据这个特点,使用本地事务即可进行事务回滚(对于重要的业务,不建议使用)。


//处理业务

@Transactional(rollbackFor = Exception.class)

public void doBussiness(Params param){


//处理本地业务

Object o = doBussiness1(param);


//rpc调用服务

ledgerProxy.batchUpdateLedgerByVersion(o);

}

处理过程:

1.处理本地业务完成后,即可调用远程服务处理业务,当都正常执行完成时,业务即处理完成。

2.若本地处理失败,则不会调用远程业务,处理中断。

3.若远程调用应用业务处理异常,则远程应用依靠自身处理进行回滚,异常抛出到本地可以使本地业务进行回滚。

缺点:

1.只能进行一个远程应用的调用,一个以上则无法进行回滚。

2.若是rpc框架的异常(超时等),也无法进行回滚。


2.使用异步消息

使用mq将数据传给其他应用,由其他应用处理接下来的业务,这种方式可以用于数据并发较大的情况,本地业务处理简单的、耗时较短的业务,其他耗时的,关键的业务发送到mq,由mq消费者进行处理。这样做即便业务失败了也可以在排查问题后重发mq进行消费从而重新处理业务。


//处理业务

@Transactional(rollbackFor = Exception.class)

public void doBussiness(Params param){


//处理本地业务

Object o = doBussiness1(param);


//rpc调用服务

sendMsg(o);

}


//发送消息

public void sendMsg (Object data){

        JSONObject jsonObject = (JSONObject) JSONObject.toJSON(data);

       NrosMQMessage nrosMQMessage = NrosMQMessage.buildNrosMQMessage(jsonObject, "topic");

       defaultZMQProducer.getProducer().sendAsync(nrosMQMessage.getMqMessage(), new SendCallback() {

     @Override

           public void onSuccess(SendResult sendResult) {}

  @Override

           public void onException(OnExceptionContext onExceptionContext) {

//失败重试

}

 });

}

// 消费消息(push方式)

@Component

public class StockUpdateConsumer extends AbstractZMQHandler {

   @Override

   public Action doBusinesses(NrosMQMessage anyoMsg, ConsumeContext consumeContext) {

            try {

    //doAnyThing 业务处理

   }catch(Exception e){

    return Action.ReconsumeLater;

   }

   return Action.CommitMessage;

}

}

处理过程:

1.先处理本地业务,将剩下的业务数据用mq进行发送,若发送失败,则本地回滚,若发送成功,则不再关心后面的处理。

2.消费者监听mq的topic收到消息后进行处理,消费失败可以重发消息处理。

缺点

1.mq消息的的固有问题需要解决,如消息重复消费,消息消费失败,或消息发送失败等问题需要解决。


3.使用分布式事务框架

使用的是阿里的f分布式事务框架,全称为Taobao Transaction Constructor,需要在maven引入txc-client和txc-client-springcloud,其中txc-client-springcloud的作用主要是设置servlet过滤器和Fegin和RestTemplate的拦截器,用于传播txc的全局事务id,txc-client本身也对一些rpc框架创建了拦截器用于传播事务id。txc-client则是txc分布式事务的实现,txc的使用需要给每个服务都进行txc配置,并建txc_undo_log用于事务日志记录并回滚。用法非常简单,只要在服务调用端使用@TxcTransaction注解即可,txc虽然可以分为好几种模式,但这里只用标准模式即可

@TxcTransaction

public void doBussiness(Params param){

//rpc调用服务1

ledgerProxy.batchUpdateLedgerByVersion(o);


//rpc调用服务2

ledgerProxy.batchUpdateBatchByVersion(o);

}

处理过程:

1.txc连接服务器申请开启全局事务,并获取一个全局事务id。

2.事务id随rpc框架在调用链路中传播,并在获取connection并开启事务前向txc服务器注册新的分支事务。

3.每个分支事务提交或回滚时向服务器发送事务执行状态信,并记录事务日志。

4.服务器汇总分支事务执行信息,通知其他分支事务回滚或提交,其中回滚需要执行上一步保存的事务日志中的sql进行回滚。




相关实践学习
快速体验阿里云云消息队列RocketMQ版
本实验将带您快速体验使用云消息队列RocketMQ版Serverless系列实例进行获取接入点、创建Topic、创建订阅组、收发消息、查看消息轨迹和仪表盘。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
Java 调度 流计算
有没有 大佬用 springboot 启动flink 处理 ,发现springboot 加 schedule调度处理会内存占满情况?
有没有 大佬用 springboot 启动flink 处理 ,发现springboot 加 schedule调度处理会内存占满情况?
422 6
|
Java Android开发
Idea使用系列之一:Idea设置类注释模板和方法注释模板
现在Idea越来越流行了,自己慢慢开始从Eclipse转向Idea开发。刚开始使用Idea,肯定会遇到各种各样的设置问题,所以在博客上专门有个文章系列进行记录,希望给转Idea开发的同学一点帮助。 设置类模板 设置方法模板
Idea使用系列之一:Idea设置类注释模板和方法注释模板
|
存储 人工智能 运维
重磅!阿里云可观测产品家族全新升级,AI +数据双驱动,打造全栈可观测体系
近日,阿里云可观测产品家族正式发布云监控 2.0,隶属产品日志服务 SLS、云监控 CMS、应用实时监控服务 ARMS 迎来重磅升级。
1053 109
|
Arthas 运维 容灾
阿里云中间件开源往事(2)
阿里云中间件开源往事
441 76
|
存储 关系型数据库 MySQL
MySQL删除索引的方法与注意事项
MySQL删除索引的方法与注意事项
1690 0
|
NoSQL 安全 Linux
springboot+shiro+redis前后端分离实现认证(一)
springboot+shiro+redis前后端分离实现认证(一)
368 0
|
消息中间件 存储 Kafka
微服务中常用的几种通信方式
微服务中常用的几种通信方式
|
数据库 测试技术 Java
阿里技术专家详解DDD系列 第二弹 - 应用架构
应用架构,指软件系统中固定不变的代码结构、设计模式、规范和组件间的通信方式。在应用开发中架构之所以是最重要的第一步,因为一个好的架构能让系统安全、稳定、快速迭代。但是今天我们在做业务研发时,更多会关注一些宏观的架构,而忽略了应用内部的架构设计,希望能通过案例分析和重构,推演出一套高质量的DDD架构。
57441 24
阿里技术专家详解DDD系列 第二弹 - 应用架构
|
NoSQL Redis Docker
Mac上轻松几步搞定Docker与Redis安装:从下载安装到容器运行实测全程指南
Mac上轻松几步搞定Docker与Redis安装:从下载安装到容器运行实测全程指南
1469 0
|
存储 缓存 数据库
Shiro【核心功能、核心组件、项目搭建 、配置文件认证、数据库认证 】(一)-全面详解(学习总结---从入门到深化)
Shiro【核心功能、核心组件、项目搭建 、配置文件认证、数据库认证 】(一)-全面详解(学习总结---从入门到深化)
596 1