分布式事务最终一致性的方案

news2024/11/18 15:31:40

最终一致性的方案

知识储备

分布式系统中不可避免存在分布式事务带来的一致性问题。为了解决这个问题,需要熟悉业界相关的理论:

  • ACID

  • CAP

  • BASE

  • 2PC

  • 3PC

  • TCC

对于一致性的处理,分为强一致和最终一致性。强一致,对系统的吞吐量和性能有较大损耗,一般用在金融/银行系统,而最终一致性,是以牺牲短期的数据强一致、提升可用性的方案。 对于大部分分布式系统,强烈建议放弃强一致性,采取最终一致性方案。

跨系统调用存在的问题

同步调用

  • 现状:微服务之间采用HTTP调用,在一个事务内涉及跨系统调用,未考虑过事务一致性问题

  • 问题:在异常情况下一定出现数据不一致和脏数据

  •  

异步消息

  • 现状:采用消息队列进行模块解耦,相比第一方案,在吞吐量和可用性方面是更好选择。我们来分析下该方案

  • 问题:出现数据不一致

场景本地事务消息处理出现原因数据一致
1本地处理成功消息发送成功一致
2本地处理成功消息发送失败- 消息服务出问题
  • 消息没有正确投递 | 没有不一致 | | 3 | 本地处理失败 | 消息发送失败 | | 没有不一致 | | 4 | 本地处理失败 | 消息发送成功 | - 发消息客户端超时,消息服务端成功

  • 发消息成功,然后A系统突然挂了 | 不一致 |

  •  

业界最终一致性方案

本地消息表

该方案的核心:

  1. 在发起远程调用前,先将远程调用的上下文持久化到一个消息表中,并要求消息表的操作与业务表的操作在一个本地事务中,然后通过异步机制去做远程调用。

  2. 消息表中维护了远程调用操作的状态机,当远程调用成功后,需要标记状态为成功。

  3. 有一点需要注意:如果遇到异步调用没有成功触发(网络原因或系统down机),需要有补偿重试机制,扫描本地消息表的数据,触发远程调用直到成功。

该方案实现方式较重,需要在每个使用该方案的业务系统专门维护一张消息表。

 

外部消息表

也称可靠型消息。和本地消息表的区别在于,将消息表移到了云端,由消息中间件统一管理消息的状态机,负责消息的初始化、重投、删除。RocketMQ是典型的例子。

 

 

Seata

Seata总共提供了4种模式,分别为AT、TCC、SAGA、XA。其中XA是强一致的,性能较差。

AT

AT是Seata主推的模式,是基于改进后的二阶段协议实现的。其技术核心是在每个服务的业务数据库中创建一个undolog表。

  1. 在事务第一阶段,Seata确保业务表与undolog表的操作在一个本地事务内。 在undolog表中,会分别记录事务提交前后的数据,称之为前镜像和后镜像,Seata框架会根据前后镜像以及当前SQL的类型,动态分析、计算出反向的回滚SQL。

  2. 在事务二阶段,如果需要提交,则会删除undolog;如果需要回滚,则Seata框架会执行底层自动生成的回滚SQL。

AT模式不能保证强一致,会存在中间状态,性能较高。AT要求我们拥有每个数据库的管理权,适用于企业内部的系统。

TCC

TCC是广为人知的模式,分为try、confirm、cancel三阶段。

try阶段就是对资源进行预占用,这个就需要对业务模型进行改造,增加中间态字段。

典型的例子,需要在单据表中增加维护预锁定资源的信息,例如锁定库存、预占用金额等。

confirm阶段和cancel阶段,将锁定资源释放,刷新实际资源信息,刷新库存、实际金额等。

TCC不是强一致的,同样存在中间状态的数据。它对业务系统的侵入性很高,所以使用场景比较局限。TCC和AT一样,要求我们拥有每个数据库的管理权。

SAGA

SAGA是基于状态机实现的二阶段协议。其原理:针对每个分支事务的正向业务逻辑,都要求提供一个反向的逻辑实现,以便在出现异常时可以调用反向逻辑进行回滚。SAGA的正向逻辑和反向逻辑,都需要程序员去实现,使用成本较高。它比较适用于长事务场景,尤其是涉及和第三方系统进行交互的场景(业务数据库无法由我方管理)。SAGA不是强一致的,同样存在中间态的数据。

事务消息接入

对数据一致性有要求的场景,可以使用rocketmq的事务型消息,接入比较简单。

使用方式

TransactionMQProducer,区别于发普通消息的DefaultMQProducer

@Override
​
public TransactionSendResult sendMessageInTransaction(final Message msg,
​
    final Object arg) throws MQClientException {
​
    if (null == this.transactionListener) {
​
        throw new MQClientException( "TransactionListener is null" , null);
​
    }
​
    return this.defaultMQProducerImpl.sendMessageInTransaction(msg, null, arg);
​
}

TransactionMQProducer初始化时要设置一TransactionListener。

事务提交和事务回查都在TransactionListener实现。

public interface TransactionListener {
​
    /**
 * When send transactional prepare(half) message succeed, this method will be invoked to execute local transaction.
 *  @param msg Half(prepare) message
 *  @param arg Custom business parameter
 *  @return Transaction state
 */
​
    LocalTransactionState executeLocalTransaction(final Message msg, final Object arg);
​
​
​
    /**
 * When no response to prepare(half) message. broker will send check message to check the transaction status, and this
 * method will be invoked to get local transaction status.
 *  @param msg Check message
 *  @return Transaction state
 */
​
 LocalTransactionState checkLocalTransaction(final MessageExt msg);

事务状态

public enum LocalTransactionState {      COMMIT_MESSAGE,      ROLLBACK_MESSAGE,      UNKNOW,  } 

executeLocalTransaction方法

有两种接入方法:

  • 标准的实现,是将本地的事务逻辑都写在此方法内部,但缺点是对代码的侵入性较大,尤其是当要对老代码进行改造时难度较大

  • 另外一种取巧的方法,本地事务逻辑正常写在其他处,然后在executeLocalTransaction方法中返回UNKNOW 状态,这样就完全依靠回查来决定事务的提交状态。

checkLocalTransaction方法

在此方法中汇报本地事务的提交、回滚状态。一般需要通过查询业务表来实现。 以电商系统为例,在订单生成时,发送消息通知物流系统生成物流单据,由于写入订单单据和发送消息要求保证原子性,而本地事务的状态,可以通过判断订单单据是否写入来判断,故checkLocalTransaction的逻辑是:根据订单号查询订单的记录

  • 如果订单记录不存在,表明事务未提交,需返回COMMIT_MESSAGE

  • 如果订单记录存在,表明事务提交,需返回ROLLBACK_MESSAGE

  • 如果方法执行异常,返回UNKNOW,等待rockermq下一次重试回调

总结

本文介绍了分布式系统下最终一致性的常用解决方案,包括本地消息表、事务消息、seata的几种事务模式,他们都有对应的场景。

  1. 本地消息表是一个可以满足多数业务要求的场景,可用性较高,如果不希望引入其他中间件,可以考虑该方案。在具体实践中,可以将消息的持久化、异步分发远程调用、补偿重试等共性逻辑封装成组件。

  2. 事务消息有比较广泛的使用场景,稳定性有保障,但由于依赖消息中间件,稳定性不如本地消息表,另外在出现问题时排查不大方便,建议对于链路监控多做考虑。

  3. seata的几种模式本文有详细介绍,在实践中要因地制宜的选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/63120.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cox回归RCS阈值效应函数cut.tab1.3发布

写在前面的话,本次只发布了cox回归RCS阈值函数,请看清楚再购买,觉得贵的可以等一等,这个函数最终会放在ggrcs包上面,免费供大家使用,急用的可以先看看。 接下来聊聊cox回归RCS阈值函数是干什么用的&#xf…

[附源码]Python计算机毕业设计SSM江西婺源旅游文化推广系统(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

Python入门 函数 基础入门篇

一、什么是函数 函数是最基本的一种代码抽象的方式,是组织好的可重复使用的,用来实现单一或相关联功能的代码段。 函数是对做相似的事情或相似的动作进行封装,它能提高应用的模块性和代码的重复利用率。我们要封装好一个函数,首…

[附源码]计算机毕业设计设备运维平台出入库模块APPSpringboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

【STM32学习(3)】STM32——简述中断的基础知识

中断一、中断的定义二、中断的作用三、中断源(中断触发的硬件)四、中断类型五、中断优先级六、中断服务函数一、中断的定义 中断,即CPU在正常执行程序的过程中,遇到外部(IO引脚中断)/内部(定时…

Maven技术

目录 传统项目管理分析(导入jar包形式) maven组成部分 maven项目构建命令 maven高级 项目的聚合与继承 maven子父工程 需求:使用maven子父工程完成登录并跳转到首页列表 创建父工程 在父工程中以module的形式创建子模块 在父工程中以…

RocketMQ 5.0 可观测能力升级:Metrics 指标分析

作者:玄珏 从消息的生命周期看可观测能力 在进入主题之前先来看一下 RocketMQ 生产者、消费者和服务端交互的流程: message produce and consume process RocketMQ 的消息是按照队列的方式分区有序储存的,这种队列模型使得生产者、消费者和…

Matlab论文插图绘制模板第67期—三角网格图(Trimesh)

在之前的文章中,分享了Matlab网格曲面图的绘制模板: 以及一些特殊形式的网格曲面图: 这一次,再来分享一种特殊的网格曲面图:三角网格图。 先来看一下成品效果: 特别提示:Matlab论文插图绘制模板…

为初学者介绍轻量级目录访问协议——LDAP

如果您是刚接触Active Directory (AD)的初学者,那么当您发现LDAP这个术语时可能会感到十分迷茫。今天就让我们来您熟悉 LDAP,让您更加坚定学习AD域管理的信心。 LDAP 首先,让我们直面主题!什么是 LDAP? LDAP 是一种标…

[矩阵论] Unit 3. 矩阵的分解 - 知识点整理

注: 以下内容均由个人整理, 不保证完全准确, 如有纰漏, 欢迎交流讨论参考: 杨明, 刘先忠. 矩阵论(第二版)[M]. 武汉: 华中科技大学出版社, 2005 3 矩阵的分解 3.1 常见的矩阵标准形与分解 常见标准形 等价标准形: P,QP, QP,Q 可逆 AmnPmm[Ir000]QnnA_{m\times n}P_{m\times…

[附源码]Python计算机毕业设计SSM教师职称资料管理系统(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

软件测试流程图!转行互联网职场必备!

今天给大家分享的是,在软件测试日常工作过程中,比较常见的几种测试流程图: 1.【测试立项】流程图 2.【测试计划】流程图 3.【单元测试】流程图 4.【整合测试】流程图 5.【系统测试】流程图 6.【性能测试】流程图 7.【验收测试】…

QTextStream(文本流)

QTextStream QTextStream 类为读取和写入文本提供了一个方便的接口可以在QIODevice、QBateArray、和QString中使用&#xff0c;QTextStream使用的是流运算符&#xff08;>> <<&#xff09;&#xff0c;可以更方便的读/写数据&#xff0c;QTextStream也支持对字段进…

使用 Echarts 插件完成中国地图

目录前言&#xff1a;什么是 Echarts 插件中国地图成品展示步骤&#xff1a;完成中国地图代码总结&#xff1a;前言&#xff1a; 大家都知道&#xff0c;一般情况下&#xff0c;想要使用前端设置一个 中国地图 需要使用 canvas 画布进行编写&#xff0c;不仅代码多&#xff0c…

【滤波器】基于Matlab设计巴斯 切比雪夫 椭圆 低通高通带通带阻数字滤波器附GUI界面

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

11月VR大数据:SteamVR新增PICO 4串流数据统计

Hello大家好&#xff0c;每月一期的VR内容/硬件大数据统计又和大家见面了。 想了解VR软硬件行情么&#xff1f;关注这里就对了。我们会统计Steam平台的用户及内容等数据&#xff0c;每月初准时为你推送&#xff0c;不要错过喔&#xff01; 本数据报告包含&#xff1a;Steam VR硬…

暖通锅炉远程监控解决方案

现状及需求分析 随着科学技术的发展&#xff0c;人们对生活品质的追求越来越高&#xff0c;空调行业也在快速发展&#xff0c;建筑空调已经成为现代城市不可或缺的重要组成部分。一般楼宇大厦都采用大型空调机组供暖制冷&#xff0c;那如何保证设备能恒温正常运行&#xff1f;…

[Python图像处理] 使用OpenCV检测对象颜色

使用OpenCV检测对象颜色前言使用 OpenCV 检测对象颜色相关链接前言 检测图像中对象颜色的一种简单方法是首先将图像从 RGB 转换为 HSV 颜色空间&#xff0c;然后使用一系列色调检测对象&#xff0c;这可以通过使用 OpenCV 库轻松完成。为了完成对象检测任务&#xff0c;我们需…

【论文合集】2022年12月医学影像期刊论文合集

★ 本月IEEE Transactions on Medical Imaging(1区 top if 11.037) 共41篇, 本月无MIA。 ”标题高频词汇 (learning, 13), (imaging, 6), (image, 6), (segmentation, 6), (network, 6), (deep, 5), (images, 5), (medical, 4), (multiple, 4), (dynamic, 4), (mri, 4), (magn…

《痞子衡嵌入式半月刊》 第 40 期

痞子衡嵌入式半月刊&#xff1a; 第 40 期 这里分享嵌入式领域有用有趣的项目/工具以及一些热点新闻&#xff0c;农历年分二十四节气&#xff0c;希望在每个交节之日准时发布一期。 本期刊是开源项目&#xff08;GitHub: JayHeng/pzh-mcu-bi-weekly&#xff09;&#xff0c;欢…