当前位置: 首页 > article >正文

跟着deepseek浅学分布式事务(2) - 两阶段提交(2PC)

文章目录

  • 一、核心角色
  • 二、流程详解
  • 三、关键示例
  • 四、致命缺点
  • 五、改进方案
  • 六、适用场景
  • 七、伪代码
    • 1. 参与者(Participant)
    • 2. 协调者(Coordinator)
    • 3. 模拟运行(Main Class)
    • 4. 关键问题模拟
  • 八、待改进问题
  • 总结


一、核心角色

  • 协调者(Coordinator):事务的发起者,负责决策提交或回滚。
  • 参与者(Participants):实际执行事务的资源管理器(如数据库、服务)。

二、流程详解

阶段一:准备阶段(Prepare Phase)

  1. 协调者向所有参与者发送Prepare请求,附带事务内容(例如:“扣除A账户100元”)。
  2. 参与者执行本地事务操作(但不提交),记录Undo/Redo日志(为回滚或重试做准备)。
  3. 参与者反馈结果:
    • 同意:回复Yes(表示已准备好,保证能提交)。
    • 拒绝:回复No(可能因约束冲突、网络超时等)。

阶段二:提交/回滚阶段(Commit/Rollback Phase)

  • Case 1: 所有参与者回复Yes
    1. 协调者发送Commit命令。
    2. 参与者完成本地提交,释放锁资源。
    3. 参与者回复Ack确认。
    4. 协调者在收到所有Ack后标记事务完成。
  • Case 2: 任一参与者回复No或超时
    1. 协调者发送Rollback命令。
    2. 参与者利用Undo日志回滚,释放资源。
    3. 参与者回复Ack
    4. 协调者标记事务终止。

三、关键示例

场景:从账户A向账户B转账100元(A和B位于不同数据库)。

  • 协调者:转账服务。
  • 参与者:数据库A(扣款)、数据库B(存款)。

执行流程

  1. Prepare阶段
    • 协调者问数据库A:“能否扣除100元?”
      • A检查余额≥100,锁定该行,记录日志,回复Yes
    • 协调者问数据库B:“能否增加100元?”
      • B检查账户有效,记录日志,回复Yes
  2. Commit阶段
    • 协调者收到所有Yes,发送Commit
    • A提交扣除操作,B提交增加操作。

若任一数据库在Prepare阶段失败(如A余额不足)

  • 协调者发送Rollback,A/B回滚操作,释放锁。

四、致命缺点

a) 同步阻塞(Blocking)

  • 参与者在Prepare后进入阻塞状态,等待协调者指令。若协调者宕机,参与者资源被长期锁定(可能导致系统僵死)。

b) 单点故障(SPOF)

  • 协调者宕机时:
    • 若在Prepare阶段:参与者无法得知最终决定,只能等待(或超时后自行回滚,破坏一致性)。
    • 若在Commit阶段:部分参与者可能已提交,导致数据不一致。

c) 数据不一致风险

  • 网络分区时:协调者仅收到部分Yes,可能误判为全部同意(需依赖超时机制补救)。
  • 部分Commit失败:某些参与者收到Commit后崩溃,未执行提交。

五、改进方案

  • 超时机制:参与者等待超时后自动回滚(但无法完全避免不一致)。
  • 三阶段提交(3PC):引入CanCommit阶段和超时中断,减少阻塞时间(仍非完美)。
  • 替代方案:TCC、SAGA等通过业务层补偿解决2PC的痛点。

六、适用场景

  • 强一致性需求:如金融核心交易(容忍低性能,追求严格一致)。
  • 短事务:长时间阻塞会加剧问题。

七、伪代码

1. 参与者(Participant)

public class Participant {private String id;private boolean prepared = false;private boolean committed = false;private Map<String, Integer> data;  // 模拟数据库(账户余额)public Participant(String id) {this.id = id;this.data = new HashMap<>();this.data.put("balance", 100);  // 初始余额100}/*** 准备阶段(Phase 1)** @param txId   事务ID* @param amount 操作金额(正数存款,负数扣款)* @return true/false 表示是否准备成功*/public boolean prepare(String txId, int amount) {try {// 检查业务约束(例如余额是否足够)if (data.get("balance") + amount >= 0) {prepared = true;    // 锁定资源,记录undo日志(伪代码)System.out.println("[Participant " + id + "] Prepared for TX " + txId);return true;} else {return false;}} catch (Exception e) {return false;   // 模拟失败(如超时、异常)}}/*** 提交阶段(Phase 2)*/public boolean commit(String txId, int amount) {if (!prepared) {return false;   // 未准备成功,拒绝提交}data.put("balance", data.get("balance") + amount);  // 执行提交committed = true;System.out.println("[Participant " + id + "] Committed TX " + txId);return true;}/*** 回滚阶段(Phase 2)*/public boolean rollback(String txId) {if (prepared && !committed) {prepared = false;   // 释放资源(伪代码)System.out.println("[Participant " + id + "] Rolled back TX " + txId);return true;}return false;}public int getBalance() {return data.get("balance");}}

2. 协调者(Coordinator)

public class Coordinator {private List<Participant> participants = new ArrayList<>();public void addParticipant(Participant participant) {participants.add(participant);}/*** 执行两阶段提交** @param txId       事务ID* @param operations 参与者操作映射* @return true/false 表示事务是否成功*/public boolean execute2PC(String txId, Map<Participant, Integer> operations) {// ----------- Phase 1: Prepare -----------List<Participant> preparedParticipants = new ArrayList<>();for (Map.Entry<Participant, Integer> entry : operations.entrySet()) {Participant p = entry.getKey();int amount = entry.getValue();if (!p.prepare(txId, amount)) {rollbackAll(txId, preparedParticipants);return false;}preparedParticipants.add(p);}// ----------- Phase 2: Commit -----------for (Map.Entry<Participant, Integer> entry : operations.entrySet()) {Participant p = entry.getKey();int amount = entry.getValue();if (!p.commit(txId, amount)) {System.out.println("[ERROR] Partial commit failed!");return false; // 部分提交失败(需人工干预)}}System.out.println("[Coordinator] TX " + txId + " successfully committed!");return true;}/*** 回滚所有已准备的参与者*/private void rollbackAll(String txId, List<Participant> participants) {for (Participant p : participants) {p.rollback(txId);}}}

3. 模拟运行(Main Class)

public class Main {public static void main(String[] args) {// 初始化协调者和参与者(模拟两个数据库)Coordinator coordinator = new Coordinator();Participant dbA = new Participant("DB-A");  // 初始余额100Participant dbB = new Participant("DB-B");  // 初始余额100coordinator.addParticipant(dbA);coordinator.addParticipant(dbB);// 模拟转账:A向B转账50(A扣50,B加50)Map<Participant, Integer> map = new HashMap<>();map.put(dbA, -50);  // A扣50map.put(dbB, 50);   // B加50boolean success = coordinator.execute2PC("TX-001", map);if (success) {System.out.println("Transaction succeeded!");System.out.println("A余额:" + dbA.getBalance());System.out.println("B余额:" + dbB.getBalance());} else {System.out.println("Transaction failed!");}}}

4. 关键问题模拟

// 1. 全部成功
[Participant DB-A] Prepared for TX TX-001
[Participant DB-B] Prepared for TX TX-001
[Participant DB-A] Committed TX TX-001
[Participant DB-B] Committed TX TX-001
[Coordinator] TX TX-001 successfully committed!
Transaction succeeded!
// 2. Prepare阶段失败(DB-B余额不足)
// 修改DB-B的初始余额为0
Participant dbB = new Participant("DB-B");
dbB.data.put("balance", 0); // 余额不足,无法扣款[Participant DB-A] Prepared for TX TX-001
[Coordinator] Participant failed to prepare. Aborting TX TX-001
[Participant DB-A] Rolled back TX TX-001
Transaction failed!

八、待改进问题

  1. 协调者单点故障:需通过日志持久化 + 备用协调者恢复。
  2. 网络超时:添加超时机制,避免无限阻塞。
  3. 幂等性:参与者需支持重复提交/回滚(相同事务ID)。
  4. 锁优化:长时间Prepare会阻塞其他事务,需优化锁粒度。

总结

这些资料整理自DeepSeek,如有版权问题请联系我进行修改。

相关文章:

跟着deepseek浅学分布式事务(2) - 两阶段提交(2PC)

文章目录 一、核心角色二、流程详解三、关键示例四、致命缺点五、改进方案六、适用场景七、伪代码1. 参与者&#xff08;Participant&#xff09;2. 协调者&#xff08;Coordinator&#xff09;3. 模拟运行&#xff08;Main Class&#xff09;4. 关键问题模拟 八、待改进问题总…...

【仿生机器人软件架构】通过整合认知系统实现自主精神性——认知系统非常具有可执行性

来自Claude 4.0 pro深度思考 仿生机器人软件架构&#xff1a;通过整合认知系统实现自主精神性 要创建具有真正情感深度的、完全自主的仿生机器人&#xff0c;需要超越基于规则的系统&#xff0c;转向能够实现涌现行为、自适应个性和类似意识处理的架构。根据截至2024年初的现…...

20250602在Ubuntu20.04.6下修改压缩包的日期和时间

rootrootrootroot-X99-Turbo:~$ ll -rwxrwxrwx 1 rootroot rootroot 36247187308 5月 23 10:23 Android13.0地面站.tgz* rootrootrootroot-X99-Turbo:~$ touch 1Android13.0地面站.tgz rootrootrootroot-X99-Turbo:~$ ll -rwxrwxrwx 1 rootroot rootroot 36247187308 6月…...

Fullstack 面试复习笔记:项目梳理总结

Fullstack 面试复习笔记&#xff1a;项目梳理总结 之前的笔记&#xff1a; Fullstack 面试复习笔记&#xff1a;操作系统 / 网络 / HTTP / 设计模式梳理Fullstack 面试复习笔记&#xff1a;Java 基础语法 / 核心特性体系化总结 这篇笔记主自用&#xff0c;系统地梳理一下最近…...

星闪开发之Server-Client 指令交互控制OLED灯案例

系列文章目录 星闪开发之Server-Client 指令交互控制OLED灯案例 文章目录 系列文章目录前言一、核心流程服务端客户端 二、图片资源三、源代码四、在Hispark Studio中配置将sle_oled-master文件夹下的相sle_oled放在peripheral文件夹下。peripheral目录下的 Kconfig文件中添加…...

MySQL补充知识点学习

书接上文&#xff1a;MySQL关系型数据库学习&#xff0c;继续看书补充MySQL知识点学习。 1. 基本概念学习 1.1 游标&#xff08;Cursor&#xff09; MySQL 游标是一种数据库对象&#xff0c;它允许应用程序逐行处理查询结果集&#xff0c;而不是一次性获取所有结果。游标在需…...

《前端面试题:CSS有哪些单位!》

CSS单位大全&#xff1a;从像素到容器单位的前端度量指南 精通CSS单位是构建响应式、灵活布局的关键技能&#xff0c;也是面试中的必考知识点 一、CSS单位的重要性与分类 在网页设计中&#xff0c;CSS单位是控制元素尺寸、间距和定位的基础。不同的单位提供了不同的计算方式和…...

[ctfshow web入门] web80

信息收集 过滤了php和data if(isset($_GET[file])){$file $_GET[file];$file str_replace("php", "???", $file);$file str_replace("data", "???", $file);include($file); }else{highlight_file(__FILE__); }解题 大小写…...

【设计模式-4.5】行为型——迭代器模式

说明&#xff1a;本文介绍设计模式中&#xff0c;行为型设计模式之一的迭代器模式。 定义 迭代器模式&#xff08;Iterator Pattern&#xff09;&#xff0c;也叫作游标模式&#xff08;Cursor Pattern&#xff09;&#xff0c;它提供一种按顺序访问集合/容器对象元素的方法&…...

C++_核心编程_继承中的对象模型

继承中的对象模型 **问题&#xff1a;**从父类继承过来的成员&#xff0c;哪些属于子类对象中&#xff1f; * 结论&#xff1a; 父类中私有成员也是被子类继承下去了&#xff0c;只是由编译器给隐藏后访问不到 */ class Base { public:int m_A; protected:int m_B; private:int…...

使用cephadm离线部署reef 18版并配置对接openstack

源 curl --silent --remote-name --location https://download.ceph.com/rpm-squid/el9/noarch/cephadm chmod x cephadm./cephadm add-repo --release reef监视节点 离线下载 apt-get --download-only install ceph ceph-mon ceph-mgr ceph-commonmkdir /reef/mon mv /var/…...

Redis最佳实践——性能优化技巧之缓存预热与淘汰策略

Redis在电商应用中的缓存预热与淘汰策略优化 一、缓存预热核心策略 1. 预热数据识别方法 热点数据发现矩阵&#xff1a; 维度数据特征发现方法历史访问频率日访问量>10万次分析Nginx日志&#xff0c;使用ELK统计时间敏感性秒杀商品、新品上线运营数据同步关联数据购物车关…...

2024年数维杯国际大学生数学建模挑战赛D题城市弹性与可持续发展能力评价解题全过程论文及程序

2024年数维杯国际大学生数学建模挑战赛 D题 城市弹性与可持续发展能力评价 原题再现&#xff1a; 中国人口老龄化趋势的加剧和2022年首次出现人口负增长&#xff0c;表明未来一段较长时期内我国人口将呈现下降趋势。这一趋势必将影响许多城市的高质量和可持续发展&#xff0c…...

3D Gaussian splatting 06: 代码阅读-训练参数

目录 3D Gaussian splatting 01: 环境搭建3D Gaussian splatting 02: 快速评估3D Gaussian splatting 03: 用户数据训练和结果查看3D Gaussian splatting 04: 代码阅读-提取相机位姿和稀疏点云3D Gaussian splatting 05: 代码阅读-训练整体流程3D Gaussian splatting 06: 代码…...

QT聊天项目DAY13

1. 重置密码 重置密码label也要实现浮动和点击效果&#xff0c;所以将忘记密码这个标签提升为ClickedLabel 1.1 ClickedLabel的复用 由于样式表(.qss) 文件中可以写入多个控件的状态UI&#xff0c;所以为了ClickedLabel能够复用&#xff0c;将成员变量的初始化方式修改为函数…...

Web3如何重塑数据隐私的未来

在这个信息爆炸的时代&#xff0c;数据隐私已成为我们不得不面对的严峻问题。Web3&#xff0c;作为下一代互联网的代表&#xff0c;以其去中心化、用户主权和数据安全等特点&#xff0c;正在重塑数据隐私的未来。它不仅仅是技术的革新&#xff0c;更是对个人隐私保护理念的一次…...

【鸿蒙】HarmonyOS NEXT之如何正常加载地图组件

1、不支持模拟器&#xff0c;需要真机&#xff01; 2、Map地图需要在AGC上申请权限&#xff0c;需要在AGC上创建对应的项目 地址&#xff1a; AppGallery Connect 2.1 AGC中项目创建 2.1.1 添加项目 2.1.2 起个名字 2.1.3 添加应用&#xff1a; 2.1.4 选择HarmonyOS APP&…...

前端框架进化史

本内容是对 You’ll Never Manually Update the DOM Again // Here’s Why 内容的翻译与整理。 你再也不需要手工更新DOM, 以下是原因 现代 JavaScript 框架&#xff0c;如 React、Vue、Svelte、Solid、Quick&#xff0c;以及本周推出的其他 786 个框架&#xff0c;都试图做一些…...

“轻量应用服务器” vs. “云服务器CVM”:小白入门腾讯云,哪款“云机”更适合你?(场景、配置、价格对比解析)

更多云服务器知识&#xff0c;尽在hostol.com 当你第一次踏入腾讯云这个“数字百货大楼”&#xff0c;面对琳琅满目的“云产品”&#xff0c;是不是有点眼花缭乱&#xff0c;特别是看到“轻量应用服务器”和“云服务器CVM”这两位都号称能帮你“安家落户”的“云主机”时&…...

day63—回溯—全排列(LeetCode-46)

题目描述 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2&#xff1a; 输入&#x…...

(二)stm32使用4g模块(移远ec800k)连接mqtt

下面代码是随手写的&#xff0c;没有严谨测试仅供参考测试 uint8_t msgBuf[200]{"msg from mcu"}; uint8_t txBuf[250]{0}; uint16_t msgid0; uint16_t mqttTaskState0; uint16_t t100msCount0; uint8_t sendFlag10; uint8_t sendFlag20; void t100msTask1(void) { …...

防火墙iptables项目实战

目录 一、网络规划 三、环境准备与检测 1、firewall &#xff08;1&#xff09;配置防火墙各大网卡ip并禁用firewalld和selinux &#xff08;2&#xff09;打开firewall路由转发 2、PC1&#xff08;内网&#xff09; &#xff08;1&#xff09;配置ip并禁用firewalld和s…...

webpack继续学习

认识PostCSS工具 PostCSS是一个通过JS来转换样式的工具&#xff0c;这个工具可以帮助我们进行一些CSS的转换和适配&#xff0c;比如自动添加浏览器前缀&#xff0c;css样式的重置 实现这些功能需要借助于PostCSS对应的插件 自动添加浏览器前缀需要&#xff1a; npm install…...

Scrapy爬虫框架Spiders爬虫脚本使用技巧

我们都知道Scrapy是一个用于爬取网站数据、提取结构化数据的Python框架。在Scrapy中&#xff0c;Spiders是用户自定义的类&#xff0c;用于定义如何爬取某个&#xff08;或某些&#xff09;网站&#xff0c;包括如何执行爬取&#xff08;即跟踪链接&#xff09;以及如何从页面中…...

PowerBI企业运营分析—全动态盈亏平衡分析

PowerBI企业运营分析—全动态盈亏平衡分析 欢迎来到Powerbi小课堂&#xff0c;在竞争激烈的市场环境中&#xff0c;企业运营分析平台成为提升竞争力的核心工具。 该平台通过整合多源数据&#xff0c;实现关键指标的实时监控&#xff0c;从而迅速洞察业务动态&#xff0c;精准…...

docker的基本命令

容器的三大组成 镜像image 一个静态文件&#xff0c;特点&#xff1a;分层结构&#xff0c;不可更改 容器container 镜像运行的结果&#xff0c;容器可以修改&#xff0c;运行完后直接停止 仓库registry 用来存放镜像文件的地方 容器的常用命令介绍 关于镜像的命令 docker …...

【运维实战】Rsync将一台主Web服务器上的文件和目录同步到另一台备份服务器!

在管理 Web 服务器时&#xff0c;确保数据安全且在发生故障时能够快速恢复至关重要&#xff0c;备份和镜像 Web 服务器数据最可靠的方法之一是使用 rsync。 Rsync 工具可以帮助在两台服务器之间同步文件和目录&#xff0c;非常适合用于创建 Web 服务器数据的备份和镜像。 下面…...

实时通信RTC与传统直播的异同

实时通信&#xff08;RTC&#xff09;与直播虽然在音视频传输领域密切相关&#xff0c;但设计目标和实现原理是存在显著差异的。 一、核心联系 共同目标&#xff1a;均需实现音视频数据的采集、编码、传输与播放。技术重叠&#xff1a;使用相似的编码标准&#xff08;如H.264/…...

Python-正则表达式(re 模块)

目录 一、re 模块的使用过程二、正则表达式的字符匹配1. 匹配开头结尾2. 匹配单个字符3. 匹配多个字符4. 匹配分组5. Python 代码示例 三、re 模块的函数1. 函数一览表2. Python 代码示例1&#xff09;search 与 finditer2&#xff09;findall3&#xff09;sub4&#xff09;spl…...

AgenticSeek 本地部署教程(Windows 系统)

#工作记录 Fosowl/agenticSeek&#xff1a;完全本地的 Manus AI。 部署排错参考资料在文末 或查找往期笔记。 AgenticSeek 本地部署教程&#xff08;Windows 系统&#xff09; 一、环境准备 1. 安装必备工具 Docker Desktop 下载地址&#xff1a;Docker Desktop 官网 安装后启…...