百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

你知道什么是分布式事务吗(分布式事务的几种方式)

ccwgpt 2024-09-26 07:50 23 浏览 0 评论

1. 什么情况下需要使用分布式事务?

使用的场景很多,先举一个常见的:在微服务系统中,如果一个业务需要使用到不同的微服务,并且不同的微服务对应不同的数据库。

打个比方:电商平台有一个客户下订单的业务逻辑,这个业务逻辑涉及到两个微服务,一个是库存服务(库存减一),另一个是订单服务(订单数加一),示意图如下:



如果在执行这个业务逻辑时没有使用分布式事务,当库存与订单其中一个出现故障时,就很可能出现这样的情况:库存数据库的值减少了 1,但是订单数据库没有变化;或是库存没变化,多了一个订单,也就是出现了数据不一致现象。

所以在类似的场合下我们要使用分布式事务,保证数据的一致性。

2. 分布式事务的解决思路

引入:MySQL 中的两阶段提交策略

在谈分布式事务的解决思路之前,我们先来看看单一数据源是如何做事务处理的,我们可以从中获取一些启发。

我们以 MySQL 的 InnoDB 引擎为例,由于 MySQL 中有两套日志机制,一套是存储层的 redo log,另一套是 server 层的 binlog,每次更新数据都要对两个日志进行更新。为了防止写日志时只写了其中一个而没有写另外一个,MySQL 使用了一个叫两阶段提交的方式保证事务的一致性。具体是这样的:

假设创建一个这样的数据库:mysql> create table T(ID int primary key, c int);, 然后执行一条这样的更新语句:mysql> update T set c=c+1 where ID=2;

这条更新语句的执行流程是这样子的:

  1. 首先执行器会找引擎取 ID=2 这一行数据
  2. 拿到数据后会把数据进行+1 操作,然后调用引擎接口把新数据写入
  3. 引擎将数据更新到内存中,并将操作记录到 redo log 里,此时 redo log 处于 prepare 状态。但它不会提交事务,只是通知执行器已经完成任务,可以随时提交。
  4. 执行器生成这个操作的 binlog,并把 binlog 写入磁盘
  5. 最后执行器调用引擎的事务接口,把 redo log 改为提交状态,更新完成。

在上述过程中,redo log 写完后没有直接提交,而是处于 prepare 状态,等通知执行器并把 binlog 写完后,redo log 再进行提交。这个过程就是两阶段提交,这是一个精妙的设计。

可能你会问为什么要有两阶段提交?如果不采用两阶段提交的话,也就是使用一阶段提交,那就相当于按顺序执行写 redo log 和 binlog,如果写完 redo log 后系统出现了故障,那么就会只有 redo log 记录了操作,binlog 没有记录,造成数据不一致;使用两阶段提交的话,假设写完 redo log 后系统出现了故障,由于事务还没有提交,所以可以顺利回滚。

两阶段提交的设计还有什么好处?首先要奠定一个概念:一个操作执行的时间越长,这个操作就越有可能失败。打个比方,你吃饭要用 20 分钟,上厕所要用 1 分钟,在吃饭的过程中收到微信消息的概率肯定比去上厕所的过程中收到微信消息的概率大。由于在数据库中更新操作的时间要远大于提交事务的时间,所以先把更新操作做完,等所有耗时操作都做完最后再提交事务,能够最大程度保证事务执行成功。

分布式事务的两阶段提交策略

根据上述的两阶段提交策略,分布式事务也可以采取类似的办法完成事务。

在第一阶段,我们要新增一个事务管理者的角色,通过它来协调各个数据源。还是拿开头的订单案例讲解,在执行下订单的逻辑时,先让各个数据库去执行各自的事务,比如从库存中减 1,在订单库中加 1,但是完成后不提交,只是通知事务管理者已经完成了任务。



到了第二阶段,由于在阶段一我们已经收到了各个数据源是否就绪的信息,只要有一个数据源没有就绪,在第二阶段就通知所有数据源回滚;如果全部数据源都已经就绪,就通知所有数据源提交事务。



总结一下这个两阶段提交的过程就是:首先事务管理器通知各个数据源进行操作,并返回是否准备好的信息。等所有数据源都准备好后,再统一发送事务提交(回滚)的通知让各个数据源提交事务。由于最后的提交操作耗时极短,所以操作失败的可能性会很低。

那么这个两阶段提交协议可能存在什么缺点呢?很可能存在被阻塞的问题,假如其中一个数据源出现了某些问题阻塞了,既不能返回成功信息,也不能返回失败信息,那么整个事务将被阻塞。对应的策略是添加一些倒计时的操作,或者是重新发送消息。

3. 分布式事务框架 TX-LCN

讲了这么多理论的知识,下面讲解一款真正应用在生产中的分布式事务框架 TX-LCN 的运行原理。(典型的分布式事务框架不止 TX-LCN,比如还有阿里的 GTS,不过 GTS 是收费的,TX-LCN 是开源的)

我们先看一下官方文档中给出的运行原理示意图:

思路和我们上面讲的两阶段分布式事务处理流程差不多(有小不同),核心步骤分为 3 步:

  1. 创建事务组:在事务发起方开始执行业务代码之前先调用 TxManager 创建事务组对象,然后拿到事务表示 GroupId 的过程。简单来说就是对这次下订单的操作在事务管理中心里创建一个对象,拿到一个 id。
  2. 加入事务组:参与方在执行完业务方法后,将该模块的事务信息通知给 TxManager 的操作。也就是指各个数据源(各个服务)完成操作后,和事务管理中心说一声,注册一下自己。
  3. 通知事务组:发起方执行业务代码后,将发起方执行结果状态通知给 TxManager,TxManager 将根据事务最终状态和事务组的信息来通知相应的参与模块提交或回滚事务,并返回结果给事务发起方。和客户打交道的下订单服务会收到减库存和加订单是否成功消息,它会把这两个消息通知给事务管理者,事务管理者根据情况通知两个库存服务提交事务或回滚事务。

目前发现网上有一篇不错的 TX-LCN 执行源码分析文章:

文章中跟着源码走一遍会发现和上面的流程图差不多,落实到代码中有一些精彩的地方,比如:

public Object runTransaction(DTXInfo dtxInfo, BusinessCallback business) throws Throwable {
 if (Objects.isNull(DTXLocalContext.cur())) {
 DTXLocalContext.getOrNew();
 } else {
 return business.call();
 }
 log.debug("<---- TxLcn start ---->");
 DTXLocalContext dtxLocalContext = DTXLocalContext.getOrNew();
 TxContext txContext;
 // ---------- 保证每个模块在一个DTX下只会有一个TxContext ---------- //
 if (globalContext.hasTxContext()) {
 // 有事务上下文的获取父上下文
 txContext = globalContext.txContext();
 dtxLocalContext.setInGroup(true);
 log.debug("Unit[{}] used parent's TxContext[{}].", dtxInfo.getUnitId(), txContext.getGroupId());
 } else {
 // 没有的开启本地事务上下文
 txContext = globalContext.startTx();
 }
 //......
}

这段代码保证了每个模块下只会有一个 TxContext,换个说法就是假设一个业务逻辑不是操作不同的数据源,而是对同一个数据源执行多次相同的操作,那么该数据源对应的模块在 DTX 下会只有一个 TxContext

LCN 的事务协调机制

LCN 的口号是:LCN 并不生产事务,LCN 只是本地事务的协调工。大家肯定会有个疑问,它不生产事务,那么它是怎么控制各个模块在完成事务的逻辑操作之后不马上提交,而是等到 TxManager 最后一起通知各模块提交的呢?

因为每个模块都是一个 TxClient,每个 TxClient 下都有一个连接池,是框架自定义的连接池,对 Connection 使用静态代理的方式进行包装。

public class LcnConnectionProxy implements Connection {
 private Connection connection;
 public LcnConnectionProxy(Connection connection) {
 this.connection = connection;
 }
 /**
 * notify connection
 *
 * @param state transactionState
 * @return RpcResponseState RpcResponseState
 */
 public RpcResponseState notify(int state) {
 try {
 if (state == 1) {
 log.debug("commit transaction type[lcn] proxy connection:{}.", this);
 connection.commit();
 } else {
 log.debug("rollback transaction type[lcn] proxy connection:{}.", this);
 connection.rollback();
 }
 connection.close();
 log.debug("transaction type[lcn] proxy connection:{} closed.", this);
 return RpcResponseState.success;
 } catch (Exception e) {
 log.error(e.getLocalizedMessage(), e);
 return RpcResponseState.fail;
 }
 }
 @Override
 public void setAutoCommit(boolean autoCommit) throws SQLException {
 connection.setAutoCommit(false);
 }
 //......
}

连接池在没有接收到通知事务之前会一直占有着这次分布式事务的连接资源。等到最后 TxManager 通知 TxClient 时,TxClient 才会去执行相应的提交或回滚。所以 LCN 的事务协调机制相当于是拦截了一下连接池,控制了连接的事务提交。

LCN 的事务补偿机制

由于我们不能保证事务每次都正常执行,如果在执行某个业务方法时,本应该执行成功的操作却因为服务器挂机或网络抖动等问题导致事务没有正常提交,这种场景就需要通过补偿来完成事务。

在这种情况下 TxManager 会做一个标示;然后返回给发起方。告诉他本次事务有存在没有通知到的情况,然后 TxClient 再次执行该次请求事务。

原文:https://mp.weixin.qq.com/s/A426VrOJ2WVMvGLRRZoOzA

作者:炭烧生蚝

来源:微信公众号

相关推荐

详解DNFSB2毒王的各种改动以及大概的加点框架

首先附上改动部分,然后逐项分析第一个,毒攻掌握技能意思是力量智力差距超过15%的话差距会被强行缩小到15%,差距不到15%则无效。举例:2000力量,1650智力,2000*0.85=1700,则智力...

通篇干货!纵观 PolarDB-X 并行计算框架

作者:玄弟七锋PolarDB-X面向HTAP的混合执行器一文详细说明了PolarDB-X执行器设计的初衷,其初衷一直是致力于为PolarDB-X注入并行计算的能力,兼顾TP和AP场景,逐渐...

字节新推理模型逆袭DeepSeek,200B参数战胜671B,豆包史诗级加强

梦晨发自凹非寺量子位|公众号QbitAI字节最新深度思考模型,在数学、代码等多项推理任务中超过DeepSeek-R1了?而且参数规模更小。同样是MoE架构,字节新模型Seed-Thinkin...

阿里智能化研发起飞!RTP-LLM 实现 Cursor AI 1000 token/s 推理技术揭秘

作者|赵骁勇阿里巴巴智能引擎事业部审校|刘侃,KittyRTP-LLM是阿里巴巴大模型预测团队开发的高性能LLM推理加速引擎。它在阿里巴巴集团内广泛应用,支撑着淘宝、天猫、高德、饿...

多功能高校校园小程序/校园生活娱乐社交管理小程序/校园系统源码

校园系统通常是为学校、学生和教职工提供便捷的数字化管理工具。综合性社交大学校园小程序源码:同城校园小程序-大学校园圈子创业分享,校园趣事,同校跑腿交友综合性论坛。小程序系统基于TP6+Uni-app...

婚恋交友系统nuiAPP前端解决上传视频模糊的问题

婚恋交友系统-打造您的专属婚恋交友平台系统基于TP6+Uni-app框架开发;客户移动端采用uni-app开发,管理后台TH6开发支持微信公众号端、微信小程序端、H5端、PC端多端账号同步,可快速打包...

已节省数百万GPU小时!字节再砍MoE训练成本,核心代码全开源

COMET团队投稿量子位|公众号QbitAI字节对MoE模型训练成本再砍一刀,成本可节省40%!刚刚,豆包大模型团队在GitHub上开源了叫做COMET的MoE优化技术。COMET已应用于字节...

通用电气完成XA102发动机详细设计审查 将为第六代战斗机提供动力

2025年2月19日,美国通用电气航空航天公司(隶属于通用电气公司)宣布,已经完成了“下一代自适应推进系统”(NGAP)计划下提供的XA102自适应变循环发动机的详细设计审查阶段。XA102是通用电气...

tpxm-19双相钢材质(双相钢f60材质)

TPXM-19双相钢是一种特殊的钢材,其独特的化学成分、机械性能以及广泛的应用场景使其在各行业中占有独特的地位。以下是对TPXM-19双相钢的详细介绍。**化学成分**TPXM-19双相钢的主要化学成...

thinkphp6里怎么给layui数据表格输送数据接口

layui官网已经下架了,但是产品还是可以使用。今天一个朋友问我怎么给layui数据表格发送数据接口,当然他是学前端的,后端不怎么懂,自学了tp框架问我怎么调用。其实官方文档上就有相应的数据格式,js...

完美可用的全媒体广告精准营销服务平台PHP源码

今天测试了一套php开发的企业网站展示平台,还是非常不错的,下面来给大家说一下这套系统。1、系统架构这是一套基于ThinkPHP框架开发的HTML5响应式全媒体广告精准营销服务平台PHP源码。现在基于...

一对一源码开发,九大方面完善基础架构

以往的直播大多数都是一对多进行直播社交,弊端在于不能满足到每个用户的需求,会降低软件的体验感。伴随着用户需求量的增加,一对一直播源码开始出现。一个完整的一对一直播流程即主播发起直播→观看进入房间观看→...

Int J Biol Macromol .|交联酶聚集体在分级共价有机骨架上的固定化:用于卤代醇不对称合成的高稳定酶纳米反应器

大家好,今天推送的文章发表在InternationalJournalofBiologicalMacromolecules上的“Immobilizationofcross-linkeden...

【推荐】一款开源免费的 ChatGPT 聊天管理系统,支持PC、H5等多端

如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!项目介绍GPTCMS是一款开源且免费(基于GPL-3.0协议开源)的ChatGPT聊天管理系统,它基于先进的GPT...

高性能计算(HPC)分布式训练:训练框架、混合精度、计算图优化

在深度学习模型愈发庞大的今天,分布式训练、高效计算和资源优化已成为AI开发者的必修课。本文将从数据并行vs模型并行、主流训练框架(如PyTorchDDP、DeepSpeed)、混合精度训练(...

取消回复欢迎 发表评论: