彻底掌握分布式事务2PC、3PC模型(三)

Handpc
发布于 2022-6-23 17:10
浏览
0收藏

 

3PC 一致性算法
三阶段提交(3PC)是二阶段提交(2PC)的一个改良版本,引入了两个新的特性

  1. 协调者和参与者均引入超时机制,通过超时机制来解决 2PC 的同步阻塞问题,避免事务资源被永久锁定
  2. 把二阶段演变为三阶段,二阶段提交协议中的第一阶段"准备阶段"一分为二,形成了新的 CanCommit、PreCommit、do Commit 三个阶段组成事务处理协议
     彻底掌握分布式事务2PC、3PC模型(三)-鸿蒙开发者社区
    这里将不再赘述 3PC 的详细提交过程,3PC 相比较于 2PC 最大的优点就是降低了参与者的阻塞范围,并且能够在协调者出现单点故障后继续达成一致

 

虽然通过超时机制解决了资源永久阻塞的问题,但是 3PC 依然存在数据不一致的问题。当参与者接收到 PreCommit 消息后,如果网络出现分区,此时协调者与参与者无法进行正常通信,这种情况下,参与者依然会进行事务的提交

 

通过了解 2PC 和 3PC 之后,我们可以知道这两者都无法彻底解决分布式下的数据一致性

 

JDBC 操作 MySQL XA 事务
MySQL 从 5.0.3 开始支持 XA 分布式事务,且只有 InnoDB 存储引擎支持。MySQL Connector/J 从5.0.0 版本之后开始直接提供对 XA 的支持

 彻底掌握分布式事务2PC、3PC模型(三)-鸿蒙开发者社区
在 DTP 模型中,MySQL 属于 RM 资源管理器,所以这里就不再演示 MySQL 支持 XA 事务的语句,因为它执行的只是自己单一事务分支,我们通过 JDBC 来演示如何通过 TM 来控制多个 RM 完成 2PC 分布式事务

 

这里先来说明需要引入 GAV 的 Maven 版本,因为高版本 8.x 移除了对 XA 分布式事务的支持(可能也是觉得没人会用吧)

<dependencies>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.38</version>
    </dependency>
</dependencies>

这里为了保证在公众号阅读的舒适性,通过 IDEA 将多行代码合并为一行了,如果小伙伴需要粘贴到 IDEA 中,格式化一下就好了

 

因为 XA 协议的基础是 2PC 一致性算法,所以小伙伴在看代码时可以对照上面文章讲的 DTP 模型和 2PC 来进行理解以及模拟错误和执行结果

import com.mysql.jdbc.jdbc2.optional.MysqlXAConnection;import com.mysql.jdbc.jdbc2.optional.MysqlXid;import javax.sql.XAConnection;import javax.transaction.xa.XAException;import javax.transaction.xa.XAResource;import javax.transaction.xa.Xid;import java.sql.*;

public class MysqlXAConnectionTest {
    public static void main(String[] args) throws SQLException {
        // true 表示打印 XA 语句, 用于调试
        boolean logXaCommands = true;
        // 获得资源管理器操作接口实例 RM1
        Connection conn1 = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");XAConnection xaConn1 = new MysqlXAConnection((com.mysql.jdbc.Connection) conn1, logXaCommands);XAResource rm1 = xaConn1.getXAResource();
        // 获得资源管理器操作接口实例 RM2
        Connection conn2 = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");XAConnection xaConn2 = new MysqlXAConnection((com.mysql.jdbc.Connection) conn2, logXaCommands);XAResource rm2 = xaConn2.getXAResource();
        // AP(应用程序)请求 TM(事务管理器) 执行一个分布式事务, TM 生成全局事务 ID
        byte[] gtrid = "distributed_transaction_id_1".getBytes();int formatId = 1;
        try {
            // ============== 分别执行 RM1 和 RM2 上的事务分支 ====================
            // TM 生成 RM1 上的事务分支 ID
            byte[] bqual1 = "transaction_001".getBytes();Xid xid1 = new MysqlXid(gtrid, bqual1, formatId);
            // 执行 RM1 上的事务分支
            rm1.start(xid1, XAResource.TMNOFLAGS);PreparedStatement ps1 = conn1.prepareStatement("INSERT into user(name) VALUES ('jack')");ps1.execute();rm1.end(xid1, XAResource.TMSUCCESS);
            // TM 生成 RM2 上的事务分支 ID
            byte[] bqual2 = "transaction_002".getBytes();Xid xid2 = new MysqlXid(gtrid, bqual2, formatId);
            // 执行 RM2 上的事务分支
            rm2.start(xid2, XAResource.TMNOFLAGS);PreparedStatement ps2 = conn2.prepareStatement("INSERT into user(name) VALUES ('rose')");ps2.execute();rm2.end(xid2, XAResource.TMSUCCESS);
            // =================== 两阶段提交 ================================
            // phase1: 询问所有的RM 准备提交事务分支
            int rm1_prepare = rm1.prepare(xid1);int rm2_prepare = rm2.prepare(xid2);
            // phase2: 提交所有事务分支
            if (rm1_prepare == XAResource.XA_OK && rm2_prepare == XAResource.XA_OK) {
                // 所有事务分支都 prepare 成功, 提交所有事务分支
                rm1.commit(xid1, false);rm2.commit(xid2, false);
            } else {
                // 如果有事务分支没有成功, 则回滚
                rm1.rollback(xid1);rm1.rollback(xid2);
            }
        } catch (XAException e) { e.printStackTrace(); } }}

 

结言
本文通过图文并茂的方式讲解了如何保证本地事务的四大特性,分布式事务的产出背景,以及 2PC、3PC 为何不能解决分布式情况下的数据一致性,最后通过 JDBC 演示了 2PC 的执行流程。相信大家看过后也对分布式事务有了较深的印象,同时对 DTP、XA、2PC 这几种比较容易混淆的概念有了清楚的认识

 

这是《分布式事务》专栏的第一章开篇,后面陆续完成通过消息中间件、可靠消息模型、Seata XA模型完成分布式事务的文章,并对不同的实现方式进行总结利弊,挑选出合适场景使用不同的分布式事务解决方案

 

作者认为最好的学习方式那就是实战,如果没有接触过分布式事务的小伙伴,可以通过自己正在写的项目,模拟出分布式事务的业务场景,加深印象的同时也能够更好理解分布式事务解决方案相关设计思路

创作不易,文章看到这里如果有所帮助,可以点个关注支持一下,祝好。我们下期见


站在巨人的肩膀

  • 《从Paxos到Zookeeper分布式一致性原理与实践》
  • 《田守枝Java技术博客》

 

文章转自公众号:龙台的技术笔记

标签
已于2022-6-23 17:10:32修改
收藏
回复
举报
回复
    相关推荐