分布式事务的认识

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

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
相关文章
|
Kubernetes 负载均衡 应用服务中间件
kubernetes—Ingress详解
kubernetes—Ingress详解
291 0
|
7月前
|
域名解析 网络协议 安全
什么是网络协议
这段内容通过生活中的例子通俗地解释了“协议”的概念。无论是与朋友吃饭的约定、打电话的过程,还是交通规则,都体现了协议的作用——确保双方按照一致的规则行动以避免混乱。在网络世界中,协议同样重要,例如DNS帮助找到网站、HTTP实现数据交互、HTTPS保障信息安全、TCP/IP负责数据传输。这些协议共同保证了设备间高效、有序的信息交流。
500 7
|
安全 测试技术
沙箱环境通常应用于哪些场景?
沙箱环境通常应用于哪些场景?
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
9月前
|
存储 机器学习/深度学习 数据挖掘
数据湖 vs 数据仓库:你家到底该买冰箱还是建个地下室?
数据湖 vs 数据仓库:你家到底该买冰箱还是建个地下室?
1282 17
|
12月前
|
缓存 数据库 索引
所有的接口都需要幂等吗?
幂等性(Idempotency)源自数学,指多次执行某操作结果不变。在计算机科学中,它确保在网络通信、重试机制和并发操作下系统状态一致。常见应用如HTTP方法中的GET、PUT、DELETE及数据库操作中的SELECT、UPDATE、DELETE等。实现幂等性可通过唯一请求ID、数据库约束、状态检查等方法。并非所有业务都需要幂等处理,需根据业务逻辑、系统容错策略及性能复杂度权衡。
164 0
|
消息中间件 Dubbo Java
聊聊单体服务VS微服务系统
聊聊单体服务VS微服务系统
|
存储 设计模式 数据可视化
DDD新手入门:领域模型设计的七个核心概念
小米,29岁程序员,分享领域模型落地知识。文章解析领域、子域、限界上下文、领域对象、聚合、工厂与仓库等概念,助你理解领域驱动设计。
736 1
|
消息中间件 存储 Kafka
微服务中常用的几种通信方式
微服务中常用的几种通信方式
|
Kubernetes 负载均衡 应用服务中间件
Kubernetes的Ingress
Kubernetes的Ingress
365 0
Kubernetes的Ingress