【分布式事务】2PC的回滚原理

2PC的回滚原理,保证通俗易懂!


1. 场景设定

  • 协调者:银行总行(负责指挥)
  • 参与者:分行A(操作小张的账户)和分行B(操作小丽的账户)
  • 操作:小张向小丽转账100元

2. 正常流程(两阶段提交)

sequenceDiagram participant 总行 participant 分行A participant 分行B 总行->>分行A: 第一阶段:准备扣款(不真扣钱) 总行->>分行B: 第一阶段:准备收款(不真加钱) 分行A-->>总行: 可以扣款(临时冻结100元) 分行B-->>总行: 可以收款(临时记账+100) 总行->>分行A: 第二阶段:正式扣款 总行->>分行B: 第二阶段:正式加钱

3. 如果某个参与者失败(比如分行B宕机)

第一阶段就失败

  1. 总行问分行B:“能收款吗?”
    → 分行B没响应(或直接拒绝)
  2. 总行立刻下令所有分行回滚
    • 对分行A说:“取消小张的冻结!”
    • 结果:小张的钱原封不动,就像什么都没发生过。

第二阶段才失败

  1. 分行A已扣款,但分行B加钱时宕机
  2. 总行发现后,启动回滚
    • 命令分行A:“把小张的100元加回去!”(用事前记录的日志恢复)
    • 结果:小张的钱退回账户,小丽没收到钱。

4. 回滚的核心原理

关键设计

  1. 日志记录

    • 每个参与者在准备阶段会记录原始数据快照(比如小张原本有200元)。
    • 就像会计做账前先抄一遍旧数据。
  2. 锁资源

    • 准备阶段会冻结相关数据(小张的100元被临时锁定,其他人不能动)。
  3. 超时机制

    • 如果参与者长时间没响应,协调者会自动触发回滚。

代码示例(伪代码)

// 参与者(分行)的回滚逻辑
public void rollback() {
    if (hasPrepared) {  // 如果准备阶段成功了
        // 1. 查日志找到原始数据
        AccountSnapshot snapshot = log.getSnapshot();
        // 2. 恢复数据
        account.setBalance(snapshot.originalBalance);
        // 3. 释放锁
        lock.release();
    }
}

5. 为什么能保证回滚成功?

  • 事前留底:准备阶段记录了“后悔药”(日志)。
  • 强制锁定:在回滚前,相关数据不能被其他操作修改。
  • 超时兜底:就算协调者宕机,参与者等不到指令也会自动回滚。

6. 现实类比

  • 就像网购付款
    1. 你先提交订单(准备阶段冻结金额)。
    2. 如果商家发货失败,平台会自动取消订单,把钱退给你(回滚)。
    3. 如果一切正常,才真正扣款(提交)。

7. 一句话总结

2PC的回滚,就是协调者发现有人掉链子时,命令所有人“按事前记的账本恢复原状”,保证不会有人多扣钱或少收钱!

这样是不是清楚多了? 😊

posted @ 2025-06-12 09:36  佛祖让我来巡山  阅读(29)  评论(0)    收藏  举报

佛祖让我来巡山博客站 - 创建于 2018-08-15

开发工程师个人站,内容主要是网站开发方面的技术文章,大部分来自学习或工作,部分来源于网络,希望对大家有所帮助。

Bootstrap中文网