如何构造强一致性系统?理解数据一致性里的2PC和TCC模式原理,以及如何做(有图)

news2024/11/17 13:28:40

背景

首先,读这篇文章的时候你应该先了解什么是事务、什么是分布式事务。
我这里举2个例子,典型场景有两个:
1、一个应用有两个数据库,一个数据库是订单,另一个数据库是积分,要求下订单的时候同时给用户积分,不能给了积分、订单却没下成,也不能订单下成了不给积分。
2、一个应用有两个微服务,调用订单服务返回HTTP 200没什么问题,但是到积分那里返回了HTTP 500,此时因为异常抛出,前端只能提示下单失败,但实际订单已经订完了。

2PC模式

那我们为了解决问题,最先想到的就是俩数据源的事务一起提交不就完事了。但限于各种业务逻辑处理可能会有报错,所以这事得在业务代码之外封装一层框架,把业务代码代理起来才能搞。

因为多个数据库连接管理起来方便,2PC模式一般适用于单体架构,一个单体对多个数据库。可以使用atomikos之类的框架,执行过程看图,不废话。
在这里插入图片描述
无论出没出异常,所有的提交操作都会被重写的提交方法捕获,等待整个程序段执行完毕后再提交,这个被拦截的过程叫做预提交。如果这个时候有哪个环节出问题抛出异常了,则会进行整体回滚。
在这里插入图片描述
简单吧,这就是2PC的原理。说了半天原理,咱上一下核心代码:

XADataSource dataSource=new DruidXADataSource();
dataSource.setUrl(这里填写Url);
dataSource.setUsername(这里填写用户名);
dataSource.setPassword(这里填写密码);
dataSource.setDriverClassName(这里填写驱动);
dataSource.setInitialSize(最小连接池大小);
dataSource.setMaxActive(最大连接池大小);
dataSource.setValidationQuery("SELECT 1");

AtomikosDataSourceBean atomikosDs = new AtomikosDataSourceBean();
atomikosDs.setXaDataSource(dataSource);
atomikosDs.setMaxPoolSize(最大连接池大小);
atomikosDs.setMinPoolSize(最小连接池大小);
atomikosDs.setUniqueResourceName(全局唯一编码,比如ds1、ds2);
atomikosDs.init();

// 拿到连接,随便做业务,你可以产生多个Connection
Connection conn1 = atomikosDs.getConnection()

// 这个事务管理器是全局唯一、线程绑定的
TransactionManager tx=new UserTransactionManager();
// 开启分布式事务一致性
tx.begin();

// 这里写你的业务代码

// 统一提交
tx.commit();

如果你想让Spring Boot或Spring Cloud用注解来接管事务,那就写以下这两个类:

import com.atomikos.icatch.jta.UserTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;

/**
 * 事务管理器
 * @author 杨若瑜
 */
public class DbTransactionManager extends AbstractPlatformTransactionManager {
    @Override
    protected Object doGetTransaction() throws TransactionException {
        return new UserTransactionManager();
    }

    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
        UserTransactionManager tx = (UserTransactionManager) transaction;
        try {
            tx.begin();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
        UserTransactionManager tx = (UserTransactionManager) status.getTransaction();
        try {
            tx.commit();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
        UserTransactionManager tx = (UserTransactionManager) status.getTransaction();
        try {
            tx.rollback();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

/**
 * 事务管理器配置
 * @author 杨若瑜
 */
@Configuration
public class TransactionConfig {
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DbTransactionManager();
    }
}

至于数据源在哪里产生,这个就随意了,哪里都可以用。

TCC模式

首先我们先了解TCC模式下数据的状态转换
Try操作:尝试执行,数据本体不会发生变更
Confirm操作:真正执行,数据本体会发生真实变更
Cancel操作:取消执行,数据本体会恢复到Try之前的状态
图中白色的部分并不会被查询出来(类似于伪删除的查询),而蓝绿色的部分会被正常检索到。
在这里插入图片描述
那如果分布式服务应该如何做呢?看下面这张图,仔细去悟你就明白了。
在这里插入图片描述
这里只展现了Try和Confirm阶段,如果是出现了异常,则由前台服务通知分布式协调者向所有服务发送Cancel指令。这里需要注意的是,我们是假设Confirm和Cancel不会抛出任何异常,如果这俩阶段出现了异常,那必须要人工介入了。
图中所展现的方法非常的简单粗暴,事实上这些都可以被Seata接管。
这里面需要注意的是,如果为了保证数据的强一致性,第5步,服务会一直卡死在那里等待状态变为Ready。如果不想效率下降,那只有一个办法:抛出异常,让前端知道这个数据在Updating,触发Cancel。
第7步中,为什么要把数据深拷贝到协调者的Redis中,主要是为了在Cancel阶段能直接用Redis中的原始数据覆盖。
而且在此过程中需要注意考虑幂等性原则,通俗的说:如果你try的时候随机产生了一个UUID,传递给积分服务,然后Confirm的时候又产生了一个新的UUID,自然积分服务拿到新的UUID会引发不可预知的错误(比如记录错误的订单主键)。因此XID和你在Try执行过程中产生的一切随机产生的变量、受到其他数据状态影响的变量都应当被缓存记录并在Confirm的时候拿出来,也就是说我如果读某个数据的状态为1,使我这次按1的逻辑去走,几秒之后别的用户把它改成了2,那我还是按1的逻辑去走,我只管按几秒前的上下文去处理,具体做底层架构的时候可以将getter和setter方法都代理起来,如果我Try的时候调和Confirm的时候调出来的结果不一样,那可不行,所以不符合幂等性时,整个GlobalTransaction都要回滚
对于第10步中,其实所有的数据都没有被真正更新,只是更新了数据的状态,而且这里没有提到的是还有新创建的数据,状态应当是Creating,在其他功能并发检索时,应当在搜索条件中过滤掉状态为Creating的数据。

TCC的各种异常情况

突然微服务宕了

我们要考虑重启的时候移除所有Creating的数据,并将所有Updating的数据改为Ready状态。写一个Spring Boot初始化会省很多事。这里的Creating的数据因为之前宕机所以一定是调用方认为它是失败的,早已通知其他服务Cancel掉了。

突然分布式协调者宕机了

这就显示出来我们Redis存在的意义了,你有多台分布式协调者,调用方调不了它,就会重试到另一台分布式协调者上,数据还在Redis里,可以保证业务的连续。

分布式协调者在Confirm到一半的时候宕机了怎么办

没关系,同上,调用方发现在第14步发出去了返回500、Connection Refused等问题,就会进行三次重试,只要还有1个能用的协调者,就会继续发送Confirm指令。

那如果整个机房停电了呢?再结合第一个和第三个问题。

额……尽管很极端。但是还是有解决办法的,微服务自己宕机重启后会取消所有还在分布式事务里的数据,同样的,分布式协调者在启动的时候也会对所有还未Confirm的数据全部Cancel掉,挨个给微服务发指令,假设在停机的前0.01秒中别的协调者已经完成Confirm并已回写Redis,集群启动后这些数据就不会再被Cancel掉了。

后记

写这篇文章挺烧脑,不管怎样,给点个赞呗。

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

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

相关文章

el-table添加固定高度height后高度自适应

0 效果 1 添加自定义指令 新建目录src/directive/el-table 在el-table目录下新建文件adaptive.js import { addResizeListener, removeResizeListener } from element-ui/src/utils/resize-event// 设置表格高度const doResize async(el, binding, vnode) > {// 获取表格…

Vben admin - 表格组件合并单元格

需求 最近在项目中有需求需要表格合并单元格,不但内容有合并的,操作列也需要合并,找遍vben官方例子,没有实现操作列合并的,只能硬着头皮实现,还好实现了,下面具体就是实现思路; 原…

再获Gartner认可!持安科技获评ZTNA领域代表供应商

近日,全球权威市场研究与咨询机构Gartner发布了《Hype Cycle for Security in China, 2023(2023中国安全技术成熟度曲线)》报告,对2023年的20个中国安全技术领域的现状与发展趋势进行了详细的分析与解读。 其中,持安科…

mac电脑视频处理推荐:达芬奇DaVinci Resolve Studio 18 中文最新

DaVinci Resolve Studio 18是一款专业的视频编辑、调色和后期制作软件,由Blackmagic Design开发。它被广泛应用于电影、电视和广告等行业,提供了全面的工具和功能,使用户能够进行高质量的影片制作和后期处理。 以下是DaVinci Resolve Studio…

JAVA-GC日志打印配置详解

一、为什么要打印GC日志? 当服务出现内存飙高、卡顿宕机等等情况,有可能因为GC问题,所以要有日志进行排查。 二、命令详解 #打印GC详情信息 -XX:PrintGCDetails #打印GC时间戳 -XX:PrintGCDateStamps #打印触发GC原因信息 -XX:PrintGCCause …

如何选择适合的美颜SDK?

美摄美颜SDK是一款专门为企业提供美颜技术支持的SDK,可以帮助企业开发出具有高品质美颜效果的移动应用。本文将介绍美摄美颜SDK的技术特点和面向企业提供的技术支持。 一、技术特点 美摄美颜SDK采用了先进的图像处理技术和人工智能算法,能够快速准确地…

基于SSM框架的校园招聘系统的设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…

Java开发者必备:支付宝沙箱环境支付远程调试指南

🔥博客主页: 小羊失眠啦. 🔖系列专栏: C语言、Linux、Cpolar ❤️感谢大家点赞👍收藏⭐评论✍️ 文章目录 前言1. 下载当面付demo2. 修改配置文件3. 打包成web服务4. 局域网测试5. 内网穿透6. 测试公网访问7. 配置二级…

农村电力供应,这件事必须重视!

随着现代社会对持续电力供应的需求不断增加,柴油发电机成为了许多组织和企业的生命线。因此,柴油发电机监控系统的性能和可靠性对于维护连续的电力供应至关重要。 客户案例 工业设施 辽宁某大型工业设施中,柴油发电机是主要的备用电源。然而&…

伦敦银条有多大投资价值?

伦敦银本来是指存放在伦敦地下金库的实物白银银条,这个市场上银条的标准规格为1000金衡盎司。但随着信息科技技术的进步以及贵金属市场的发展,现在的伦敦银交易已经完全实现了电子化。 在当今的贵金属投资市场, 伦敦银的交易网络已经遍布全球…

写保护设置——二、NOR FLASH

二、NOR FLASH 以Winbond的W25Q16DVSSIG型NOR FLASH为例,W25Q16DVSSIG容量为16Mbit(16777216bit,2Mbit8,2097152bit8,1FFFFF8),即有2097152个地址,每个地址对应8bit数据。 2.1 状态寄存器 W25…

欧科云链联合FT中文网与香港大学,探寻Web3未来安全合规之路

在新一代科技浪潮中,Web3作为下一代互联网的演进方向正在快速发展,技术推动了虚拟资产投资市场的快速增长,机遇与风险同步上升。10月24日,美国比特币现货ETF再迎新进展,市场情绪高涨,这对于全球Web3行业的发…

Android 类似淘宝的吸顶特效解决方案

运行图 布局的设计 要实现上面的效果需要搞定NestedScrollView和RecycleView的滑动冲突。有人要问RecycleView为何要滑动自动撑大不就好了么?这个问题其实对于有限的资源加载来说是很好的解决方案,但是如果涉及到的是图文结合的并且有大批量的数据的时候…

AquilaChat2-34B 主观评测接近GPT3.5水平,最新版本Base和Chat权重已开源!

两周前,智源研究院发布了最强开源中英双语大模型AquilaChat2-34B 并在 22项评测基准中综合能力领先,广受好评。为了方便开发者在低资源上运行 34B 模型,智源团队发布了 Int4量化版本,AquilaChat2-34B 模型用7B量级模型相近的GPU资…

分享119个ASP.NET源码总有一个是你想要的

分享119个ASP.NET源码总有一个是你想要的 链接:https://pan.baidu.com/s/1Mp0RugMnIJbS8Hrja4sCOQ?pwd8888 提取码:8888 项目名称 asp.net core 微服务 项目 ASP.NET Core 项目日志解决方案 Serilog Log4net ASP.NET Core分布式项目实战 asp.n…

GMT中标注特殊字符:平方,%,±号,希腊字母

在gmt中文社区的官网,我们可以得到以下的特殊字符表,通过在cmd命令窗口输入以下命令 gmt get PS_CHAR_ENCODING 查到你所安装的GMT的默认字符编码方式。如下图所示,本人是默认的ISOLation1 编码。 下面是一些具体的特殊字符的代码与标注效果…

使用网络摄像头进行眼睛注视估计 Mediapipe Gaze track

让我们看看下面的情况,你坐在图书馆里,你刚刚看到最漂亮的女人坐在图书馆的另一边。哎呀,她发现你在盯着她看。她估计你的目光在盯着她,而你通过理解她的目光指向你,注意到被她抓个正着。 眼睛凝视:一个人的眼睛聚焦的点 就像我们惊人的大脑毫不费力地完成许多任务一样,…

stable-diffusion-ui 下载和安装

简介 Stable Diffusion Web UI是一款基于Stable Diffusion基础应用的交互程序,它利用gradio模块搭建而成。这个模块除了具有txt2img、img2img等基本功能外,还包含许多模型融合改进、图片质量修复等附加升级。所有这些功能都可以通过易于使用的Web应用程…

漏洞复现-SeaCMS_v10.1_远程命令执行(CNVD-2020-22721)

SeaCMS_v10.1_远程命令执行(CNVD-2020-22721) 漏洞信息 seacms_v10.1有效cnvd-2020-22721命令执行漏洞 描述 海洋CMS一套程序自适应电脑、手机、平板、APP多个终端入口。 SeaCMS v10.1存在命令执行漏洞,在w1aqhp/admin_ip.php下第五行使用set参数,对…

不黑箱,不抽卡,分分钟带你拿捏SD中的色彩控制 | 京东云技术团队

导言 颜色控制一直是AIGC的难点,prompt会污染、img2img太随机… 今天带来利用controlnet,实现对画面颜色的有效控制。都说AIGC是抽卡,但对把它作为工具而非玩具的设计师,必须掌握如何控制它,让我们一起开始可控AI生成…