分布式事务三阶段提交3PC详解

news2024/10/2 6:40:07

文章目录

    • 概述
    • 工作流程
    • 优缺点
    • 总结
    • 代码样例

概述

3PC 利用超时机制解决了 2PC 同步阻塞问题,避免资源被永久锁定,进一步加强了整个事务过程可靠性。但 3PC 同样无法应对类似宕机问题,只不过出现多数据源中数据不一致问题概率更小。
a. 概念:三阶段提交协议在协调者和参与者中都引入超时机制,并且把两阶段提交协议的第⼀个阶段拆分成了两步:询问,然后再锁资源,最后真正提交。这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。
三阶段提交(3PC)是二阶段提交(2PC)的一种改进版本,旨在解决2PC的一些问题,如阻塞和单点故障。3PC将二阶段提交的过程分为三个阶段:CanCommit、PreCommit和DoCommit,并引入超时机制。

工作流程

○ 准备阶段:协调者询问所有参与者是否可以执行事务提交。与2PC不同,这里的询问不是投票,而是询问是否可以安全地提交事务。参与者根据自身情况返回Yes或No。
○ 预提交阶段:如果所有参与者都返回Yes,协调者会向它们发送预提交请求。参与者执行事务操作,并将Undo和Redo日志写入本机事务日志。然后,它们发送Ack响应给协调者,等待最终的Commit或Abort指令。如果有参与者返回No或等待超时,协调者会发送中断请求,导致事务中断。
○ 提交阶段:如果协调者收到了所有参与者的Ack响应,它会从预提交状态转换到提交状态,并向所有参与者发送doCommit请求。参与者收到doCommit请求后,正式执行事务提交操作,并在完成后释放资源。协调者接收到所有参与者的Ack消息后,完成事务。
在这里插入图片描述

1.CanCommit 阶段:
○ 协调者向所有参与者发送CanCommit请求,并等待参与者的回复。
○ 参与者接收到CanCommit请求后,首先执行本地事务的预检查,检查是否存在任何可能导致事务无法提交的问题。
○ 如果参与者的预检查通过,它会发送Ack消息给协调者,表示可以提交事务。
○ 如果参与者的预检查失败,它会发送Abort消息给协调者,表示无法提交事务。
2.PreCommit 阶段:
○ 协调者收到所有参与者的Ack消息后,如果没有收到任何Abort消息,则发送PreCommit请求给所有参与者。
○ 参与者接收到PreCommit请求后,会再次执行本地事务的准备操作,并将undo和redo信息记录到日志中以便回滚或提交。
○ 如果参与者准备就绪,它会发送Ack消息给协调者。
○ 如果参与者在准备阶段遇到问题,它会发送Abort消息给协调者。
3.DoCommit 阶段:
○ 协调者在收到所有参与者的Ack消息后,如果没有收到任何Abort消息,则发送DoCommit请求给所有参与者。
○ 参与者接收到DoCommit请求后,执行事务的最终提交操作,并释放相关资源。
○ 事务提交完成后,参与者向协调者发送Ack消息,表示事务已提交。
如果在任何阶段发生超时或接收到Abort消息,协调者会中止事务并发送Abort请求给所有参与者,参与者接收到Abort请求后执行事务的回滚操作。
三阶段提交相对于二阶段提交的改进之处在于引入了超时机制,在CanCommit和PreCommit阶段都设置了超时时间。这样可以避免一些常见的问题,如网络故障、崩溃节点等导致的阻塞情况。然而,三阶段提交仍然存在一些问题,如脑裂和数据不一致的风险,因此在实际应用中需要根据具体场景进行权衡和选择。
需要注意的是,上述只是对三阶段提交的基本原理和流程进行了简要解释,实际应用中还需要考虑更多的细节和异常情况处理,以确保分布式事务的正确执行。

优缺点

优点:3PC有效降低了2PC带来的参与者阻塞范围,并且能够在出现单点故障后继续达成一致。
缺点:然而,3PC也带来了新的问题。在参与者收到preCommit消息后,如果网络出现分区,协调者和参与者无法进行后续的通信。这种情况下,参与者在等待超时后,依旧会执行事务提交,这样会导致数据的不一致。
缺点:如果进⼊PreCommit后 ,Coordinator发出的是abort请求,假设只有⼀个Cohort收到并进行了abort操作,而其他对于系统状态未知的Cohort会根据3PC选择继续Commit,此时系统状态发⽣不⼀致性。

总结

总的来说,三阶段提交是一种改进的提交协议,用于解决二阶段提交中的阻塞问题。它通过引入预提交阶段来提供更好的灵活性和容错性。然而,它也引入了新的问题,如数据不一致的风险。在实施这种算法时,需要权衡其优缺点,并确保它适合特定应用的需求。

代码样例

以下是一个简单的 Java 代码示例,演示了三阶段提交(3PC)协议的基本逻辑。在实际的生产环境中,需要考虑更多的异常情况处理、事务资源管理、并发控制等方面的细节。

// 协调者代码
public class Coordinator {
    private List<Participant> participants;

    public Coordinator(List<Participant> participants) {
        this.participants = participants;
    }

    public void startTransaction() {
        // 第一阶段:CanCommit阶段
        sendCanCommitRequestToAllParticipants();
        if (receiveAckResponsesFromAllParticipants()) {
            // 所有参与者都已经确认可以提交事务
            // 第二阶段:PreCommit阶段
            sendPreCommitRequestToAllParticipants();
            if (receiveAckResponsesFromAllParticipants()) {
                // 所有参与者都已经准备就绪
                // 第三阶段:DoCommit阶段
                sendDoCommitRequestToAllParticipants();
                receiveAckResponsesFromAllParticipants();
                // 处理事务提交结果
                handleCommitResults();
            } else {
                // 任一参与者未准备就绪,回滚事务
                sendAbortRequestToAllParticipants();
                receiveAckResponsesFromAllParticipants();
                // 处理事务回滚结果
            }
        } else {
            // 任一参与者无法提交事务
            sendAbortRequestToAllParticipants();
            receiveAckResponsesFromAllParticipants();
            // 处理事务回滚结果
        }
    }

    // 其他方法和实现细节省略
}

// 参与者代码
public class Participant {
    public boolean canCommit() {
        // 执行本地事务的预检查,判断是否可以提交事务
        return true;  // 或者 false,表示是否可以提交事务
    }

    public boolean preCommit() {
        // 执行本地事务的准备操作,并记录undo和redo信息到日志
        return true;  // 或者 false,表示准备操作是否成功
    }

    public void doCommit() {
        // 根据之前记录的undo和redo信息执行事务提交操作
    }

    public void abort() {
        // 根据之前记录的undo和redo信息执行事务回滚操作
    }

    // 其他方法和实现细节省略
}

在这个示例中,协调者负责协调整个分布式事务的执行过程,包括CanCommit、PreCommit和DoCommit阶段的处理。参与者则负责执行本地事务,并响应协调者的请求。请注意,这只是一个简化的示例,并不涵盖所有可能的情况和错误处理。在实际的系统设计中,需要根据具体情况进行更加完善的设计和实现。

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

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

相关文章

Python中json模块的使用与pyecharts绘图的基本介绍

文章目录 json模块json与Python数据的相互转化 pyecharts模块pyecharts基本操作基础折线图配置选项全局配置选项 json模块的数据处理折线图示例示例代码 json模块 json实际上是一种数据存储格式&#xff0c;是一种轻量级的数据交互格式&#xff0c;可以把他理解成一个特定格式…

Spark编程实验三:Spark SQL编程

目录 一、目的与要求 二、实验内容 三、实验步骤 1、Spark SQL基本操作 2、编程实现将RDD转换为DataFrame 3、编程实现利用DataFrame读写MySQL的数据 四、结果分析与实验体会 一、目的与要求 1、通过实验掌握Spark SQL的基本编程方法&#xff1b; 2、熟悉RDD到DataFram…

springboot实现发送邮件开箱即用

springboot实现发送邮件开箱即用 环境依赖包yml配置Service层Controller层测试 环境 jdk17 springboot版本3.2.1 依赖包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId><ver…

【OAuth2】:赋予用户控制权的安全通行证--原理篇

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于OAuth2的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.什么是OAuth? 二.为什么要用OAuth?…

第11章 GUI Page400~402 步骤二 画直线

运行效果&#xff1a; 源代码&#xff1a; /**************************************************************** Name: wxMyPainterApp.h* Purpose: Defines Application Class* Author: yanzhenxi (3065598272qq.com)* Created: 2023-12-21* Copyright: yanzhen…

《每天一分钟学习C语言·九》引用,指针函数,函数指针等

1、 普通全局变量——作用域是整个源程序&#xff08;含有多个源文件&#xff0c;在各个源文件中都有效&#xff09; static全局变量——作用域在当前源文件 2、 引用 &#xff08;1&#xff09;申明引用的同时必须要初始化 &#xff08;2&#xff09;引用变量是目标变量的一个…

Windows 11中显示文件扩展名的方法与Windows 10大同小异,但前者更人性化

默认情况下&#xff0c;Windows 11会隐藏已知文件类型的文件扩展名。这可能会使在不首先打开文件的情况下很难识别文件类型。 幸运的是&#xff0c;你可以将Windows 11配置为显示已知文件类型的扩展名。该方法类似于Windows 10&#xff0c;但该选项现在组织在下拉菜单中&#…

分布式锁功效初探——以电商问题为例

文章目录 电商库存问题单机处理-Sychronized多机器处理-分布式锁入门级别&#xff0c;用redis实现&#xff0c;setnx问题1&#xff1a;逻辑可能异常&#xff0c;造成死锁问题2&#xff1a;机器宕机问题3&#xff1a;锁一直失效&#xff0c;乱套锁续命 redisson分布式丢锁问题主…

python实现元旦多种炫酷高级倒计时_附源码【第20篇—python过元旦】

文章目录 &#x1f30d;python实现元旦倒计时 — 初级(控制台)⛅实现效果&#x1f30b;实现源码&#x1f31c;源码讲解 &#x1f30d;python实现元旦倒计时 — 中级(精美动态图)⛅实现效果&#x1f30b;实现源码&#x1f31c;源码讲解 &#x1f30d;python实现元旦倒计时 — 高…

C++使用HTTP库和框架轻松发送HTTP请求

编程中使用 HTTP 库或框架发送 HTTP 请求 一、引言二、使用Curl库发送HTTP请求三、使用Boost.Beast库发送HTTP请求四、使用cpp-httplib库发送HTTP请求五、自己实现socket发送 HTTP 请求总结 一、引言 使用C编程发送HTTP请求通常需要使用第三方的HTTP库或框架。在C中&#xff0…

57 代码审计-JAVA项目框架类漏洞分析报告

目录 过滤器及拦截器相关区别解释Struts2-016远程代码执行漏洞分析-黑盒流程SpringBoot-SpEL表达式注入漏洞分析-白盒思路 过滤器及拦截器相关区别解释 Filter是基于函数回调的&#xff0c;而Interceptor则是基于Java反射的。 Filter依赖于Servlet容器&#xff0c;而Intercept…

gitattributes配置文件的作用

0 Preface/Foreword Git版本管控工具功能强大&#xff0c;在使用过程中&#xff0c;在多人合作的项目开发过程中&#xff0c;经常会遇到提交代码时出现的warning提醒&#xff0c;尤其是换行符。 Linux/Unix/Mac OS操作系统的换行符使用LF符号&#xff08;\n&#xff09;&…

Dash中 基本的 callback 5

app.callback 在Dash中&#xff0c;app.callback 被用于创建交互性应用程序&#xff0c;它用于定义一个回调函数&#xff0c;该函数在应用程序中发生特定事件时被触发。回调函数可以修改应用程序的布局或更新图表等内容&#xff0c;从而实现动态交互。 下面是一个简单的 app.…

LaTex详细安装及配置(Windows)

文章目录 引言LaTeX简介优势与应用领域 安装环境安装texlive下载texlive安装 编辑器安装texstudio下载texstudio安装 环境配置 使用第一个LaTex文档新建文件编程查看 效果 结语 引言 在当今信息技术高度发达的时代&#xff0c;文档的编辑和排版是我们日常工作和学习中不可或缺…

JavaScript中的prototype和_proto_的关系是什么

JavaScript中的prototype和_proto_的关系是什么 __proto__ 是 JavaScript 中对象的一个内部属性&#xff0c;它指向该对象的原型。JavaScript 中每个对象都有一个 __proto__ 属性&#xff0c;通过它可以访问对象的原型。prototype 是函数对象特有的属性&#xff0c;每个函数都…

蓝桥杯 1223 第 2 场 小白入门赛

蓝桥小课堂-平方和 模拟 1 2 2 2 3 2 ⋯ n 2 n ⋅ ( n 1 ) ⋅ ( 2 n 1 ) 6 1^22^23^2\cdotsn^2\dfrac{n\;\cdot\;(n 1)\;\cdot\;(2n1)}{6} 122232⋯n26n⋅(n1)⋅(2n1)​。 write(n * (n 1) * (n * 2 1) / 6);房顶漏水啦 m a x ( 最大的行 − 最小的行 , 最大的列 −…

DevC++ 用C语言的多线程 实现简单的客户端和服务器

知识来源一&#xff1a; 使用Dev-C实现简单的客户端和服务器-CSDN博客 此先生的博客使用的是win32 SDK来创建多线程&#xff0c;然后鄙人对这个版本的多线程细节不明。于是又重新用C语言的线程替代win32API,以此继续学习服务器代码。 知识来源二&#xff1a;DevC 多线程创建…

[Netty实践] 简单WebSocket服务实现

目录 一、介绍 二、依赖导入 三、基础类准备 四、Handler实现 五、WebSocketChannelInitializer实现 六、WebSocketServer实现 七、前端实现 八、测试 九、参考链接 一、介绍 关于WebSocket此处不进行过多介绍&#xff0c;本章主要着重通过Netty实现WebSocket通信服务…

在线客服系统:解决常见问题的实用工具与解决方案

市场得不断发展促使着消费者服务意识的觉醒&#xff0c;越来越多的消费者在购买产品的时候不仅看产品的功能、外观、性能&#xff0c;还关注品牌的服务质量。在线客服系统的出现帮助企业解决了客户服务难的问题。接下来&#xff0c;我们具体聊一聊在线客服系统能解决哪些问题&a…

每日一题——LeetCode888

方法一 个人方法&#xff1a; 交换后要达到相同的数量&#xff0c;那么意味着这个相同的数量就是两个人总数的平均值&#xff0c;假设A总共有4个&#xff0c;B总共有8个&#xff0c;那么最后两个人都要达到6个&#xff0c;如果A的第一盒糖果只有1个&#xff0c;那么B就要给出6…