前言

分布式事务拆开来其实就是分布式、事务两个概念,分布式简略讲就是不同过程间的零碎进行通信;事务广义上咱们常常把它看作是数据库的事务,事务具备ACID个性即:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),艰深来说就是同一个事务中对于数据库的更新操作来说要么都胜利,要么都失败;狭义上来说同一个事务中的一批操作(非局限于数据库操作)要么都胜利,要么都失败;综合来说就是事务的参与者别离位于不同的过程节点中。

分布式实践

既然和分布式无关,那咱们很有必要理解一下分布式系统的几个实践CAP和Base实践;

CAP实践

一个分布式系统不可能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三个根本需要,最多只能同时满足其中的两项;

一致性:所有节点在同一时间具备统一的数据,以下单为例:用户订单生成,库存缩小,用户付钱等操作要么一起胜利要么一起失败;
可用性:服务始终可用,而且是失常响应工夫;
分区容错性:分布式系统在遇到某节点或网络分区故障的时候,依然可能对外提供满足一致性和可用性的服务。

对于一个分布式系统而言,分区容错性能够说是一个最根本的要求;所以大部分状况其实都是在CA两者之间进行衡量;分布式事务同样存在这样的抉择,比方上面要介绍的X/Open XA协定,更加偏向于一致性;然而面对互联网的高并发,这种强一致性引发了很大的性能问题,而基于BASE实践的柔性事务可能是更好的一个抉择;

BASE实践

BASE是Basically Available(根本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的简写。很显著BASE实践更加偏向满足CAP实践中的AP,既满足可用性,分区容忍性的零碎,通常可能对一致性要求低一些;

BASE实践和ACID能够说是齐全相同的,ACID保障的是强一致性就义可用性,BASE实践是用最终一致性代替强一致性保障可用性;在理论的场景中,不同的业务对数据的要求是不一样的,所以大部分状况下BASE实践和ACID是联合起来应用的;

基于BASE实践的柔性事务典型计划:最大致力告诉型,TCC,异步确保型等;

对于CAP,ACID,BASE实践能够通过如下图做一个直观的理解:

分布式事务场景

在介绍分布式事务场景之前,咱们首先对本地事务做一个简略的理解,也是咱们平时最罕用的事务,基本上支流的数据库都反对本地事务,也基本上都满足ACID这几个个性;

本地事务

一个过程对应一个数据库,事务的所有参与者都在一个过程内,并且对同一台数据库进行操作;

java.sql.Connection提供了对事务的提交、回滚等操作,大抵的代码如下所示:

Connection conn = DriverManager.getConnection(...) //获取数据库连贯// JDBC中默认是true,主动提交事务,false敞开主动提交conn.setAutoCommit(false);try {    // 数据库操作1    // 数据库操作2    conn.commit(); // 提交事务} catch (Exception e) {    conn.rollback();// 事务回滚} finally {    conn.close();// 敞开链接}

当然java自身没有提供对事务的反对,所有反对都是数据库提供的,比方mysql相干事务操作:

mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> insert into t_order0 (user_id,order_id) values ('110','1212');Query OK, 1 row affected (0.00 sec)mysql> insert into t_order0 (user_id,order_id) values ('111','1213');Query OK, 1 row affected (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.03 sec)

当然如果每块业务处理事务都要这么写一遍切实是麻烦,齐全能够通过AOP做切面解决,Spring就能够很好的帮咱们实现事务的解决,提供了对立的事务管理接口PlatformTransactionManager,常见的实现类:

DataSourceTransactionManager:用于治理本地事务;

JtaTransactionManager:反对分布式事务实现了JTA标准,应用XA协定进行两阶段提交;

<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource" /></bean><tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">    <tx:attributes>        ......    </tx:attributes></tx:advice><aop:config>    ......</aop:config>

既能够通过切面配置哪些类哪些办法须要做事务处理,也能够通过@Transitional注解来配置;

分布式事务

随着SOA架构、微服务的风行,分布式事务也呈现在很多场景中,常见的包含:单利用多数据源、多利用单数据源、多利用多数据源;

单利用多数据源

这种状况可能是对不同的业务对数据库做了拆分,然而利用还没做拆分,或者说数据量比拟大对数据库做了分库分表操作;

注:这里的数据源不肯定就是数据库,也可能是MQ之类的数据源;

多利用单数据源

这种状况很多呈现在应用Oracle数据库的零碎中,数据库功能强大,多个利用共用一个数据库,常见于很多金融零碎;

多利用多数据源

这种状况常见于各种SOA架构、微服务零碎中,应该说是目前最常见的场景,各个过程间通过RPC调用;

以上几种场景都会用到分布式事务,当然下面也提到CAP实践,对于分布式事务的解决形式也是会依据你的业务逻辑做相应的衡量;然而不得不提DTP模型,能够说是分布式事务处理的规范;

DTP模型与XA标准

DTP模型以及XA标准是一家叫X/Open的组织定义的行业标准;

X/Open国际联盟有限公司是一个欧洲基金会,它的建设是为了向UNIX环境提供规范。它次要的指标是促成对UNIX语言、接口、网络和利用的开放式系统协定的制订。它还促成在不同的UNIX环境之间的应用程序的互操作性,以及反对对电气电子工程师协会(IEEE)对UNIX的可移植操作系统接口(POSIX)标准。

相干标准能够参考如下文档:

DTP(Distributed Transaction Processing)模型:Distributed Transaction Processing: Reference Model

DTP(Distributed Transaction Processing)XA标准:Distributed Transaction Processing: The XA Specification

DTP模型

X/Open DTP模型包含五个基本功能组件:

  • 应用程序(AP):全称Application Program,定义事务边界并指定形成事务的操作;
  • 资源管理器(RMs):全称Resource Managers ,如数据库或文件拜访零碎,提供对资源的拜访;
  • 事务管理器(TM):全称Transaction Manager,为事务调配标识符,监控其进度,并负责事务实现和协调故障复原;
  • 通信资源管理器(CRM):全称Communication Resource Managers,用于管制TM域内或跨TM域的分布式应用程序之间的通信;
  • 通信协议(CP):全称Communication protocol,提供分布式应用程序应用并由CRM反对的底层通信服务。

模型实例

每个实例能够反对一个AP、一个TM和多个RMs。分布式应用程序由两个或多个实例示意,每个实例中都蕴含一个CRM;

这种模型能够说是最简略的模型了,对应的其实就是下面的单利用多数据源的状况;而对于分布式应用程序须要多个实例,模型如下:

能够发现每个模型实例多了一个CRM模块,次要用于分布式应用程序间的通信;能够用来解决多利用的状况;

事务管理器作用域

TM域由一个或多个应用同一TM的实例组成,此TM对于在该TM域中运行的所有应用程序都是通用的。公共TM应用逻辑共享的数据结构和日志进行全局事务管理;

当两个实例之间产生分布式通信时,它们具备上下级关系,申请另一个实例参加全局事务的实例称为下级,申请的实例称为隶属实例,特地是没有下级的实例称为根;在X/opendtp模型中,通过应用树结构来治理跨分布式ap操作的全局事务;

XA标准

下图显示了DTP零碎的本地实例,其中AP调用TM来结构事务。这些框示意X/Open DTP模型中的软件组件;箭头批示控制流的方向;

X/Open标准的主题是上图中的接口(3),即TMs和RMs交互的XA接口;

XA接口

RM和TM之间的接口定义如下所示:

  1. ax_reg:向TM注册RM;
  2. ax_unreg:用TM登记RM;
  3. xa_close:终止AP对RM的应用;
  4. xa_commit:通知RM提交事务分支;
  5. xa_complete:测试异步xa_ 操作是否实现;
  6. xa_end:勾销线程与事务分支的关联;
  7. xa_forget:容许RM放弃其对启发式实现事务分支的理解;
  8. xa_open:初始化RM以供AP应用;
  9. xa_prepare:要求RM筹备提交事务分支;
  10. xa_recover:获取RM已筹备或启发式实现的XID列表;
  11. xa_rollback:通知RM回滚事务分支;
  12. xa_start:启动或复原事务分支-将XID与RM的线程申请的将来工作相关联

二阶段提交

XA标准的根底是二阶段提交协定,XA标准对二阶段提交做了优化;二阶段提交其实就是将提交分成两个阶段,上面大抵看一下二阶段提交的流程:

第一阶段:预提交阶段
1.事务询问:协调者会问所有的参与者节点,是否能够执行提交操作
2.执行事务:各个参与者执行事务操作 如:资源上锁,将Undo和Redo信息记入事务日志中
3.参与者向协调者反馈事务询问的响应:如果参与者胜利执行了事务操作,反馈给协调者Yes响应,否则No响应

第二阶段:执行事务提交
如果协调者从所有的参与者取得的反馈都是Yes响应,那么就会执行事务提交
1.发送提交申请:协调者向参与者发送Commit申请
2.事务提交:参与者承受到Commit申请后,会正式执行事务提交操作,并在实现提交之后开释事务资源
3.反馈事务提交后果:参与者在实现事务提交之后,向协调者发送Ack音讯
4.实现事务:协调者承受到所有参与者反馈的Ack音讯后,实现事务

如果任何一个参与者向协调者反馈了No响应,或者在期待超时之后,协调者尚无接管到所有参与者的反馈信息,那么就会中断事务
1.发送回滚申请:协调者向参与者发送Rollback申请
2.事务回滚:参与者利用Undo信息来执行事务回滚,并开释事务资源
3.反馈事务回滚后果:参与者在实现事务回滚之后,向协调者发送Ack音讯
4.中断事务:协调者接管到所有参与者反馈的Ack音讯之后,中断事务

因为二阶段提交自身存在着阻塞、单点等问题,后续呈现了改良版本三阶段提交,将第一阶段一分为二,此处不在具体介绍;

规范定义好之后,各种RM产品就要去实现这些接口,这样就能够反对分布式事务,最典型的RM包含数据库,MQ等;在一个分布式事务中RM往往是有多个的,每一个RM提供的XA反对,能够了解为一个事务分支,对立交给TM来治理;

Mysql XA反对

要想查看以后Mysql是否提供了XA反对,能够间接应用如下命令:

其中的XA用来示意是否反对,InnoDB引擎是反对的,其余不反对;

XA事务SQL语句

XA {START|BEGIN} xid [JOIN|RESUME]  //开启XA事务XA END xid [SUSPEND [FOR MIGRATE]]  //完结XA事务XA PREPARE xid  //筹备提交XA COMMIT xid [ONE PHASE]  //提交事务XA ROLLBACK xid  //回滚事务XA RECOVER  //列出所有处于PREPARE阶段的XA事务

更多能够参考:Mysql XA文档

上面是一个简略的XA事务,它将行作为全局事务的一部分插入表中:

mysql> XA START 'xatest';Query OK, 0 rows affected (0.00 sec)mysql> INSERT INTO mytable (i) VALUES(10);Query OK, 1 row affected (0.04 sec)mysql> XA END 'xatest';Query OK, 0 rows affected (0.00 sec)mysql> XA PREPARE 'xatest';Query OK, 0 rows affected (0.00 sec)mysql> XA COMMIT 'xatest';Query OK, 0 rows affected (0.00 sec)

ActiveMQ XA反对

ActiveMQ同样提供了XA相干命令反对,如下所示:

    public static final byte BEGIN = 0;  //开启事务    public static final byte PREPARE = 1;  //筹备提交    public static final byte COMMIT_ONE_PHASE = 2;  //一阶段提交    public static final byte COMMIT_TWO_PHASE = 3;  //二阶段提交    public static final byte ROLLBACK = 4;  //回滚事务    public static final byte RECOVER = 5;  //列出所有处于PREPARE阶段的XA事务    public static final byte FORGET = 6;  //容许RM放弃其对启发式实现事务分支的理解    public static final byte END = 7;  //完结XA事务

ActiveMQ通过以上字节标识来表白不同的XA接口类型;

各类RM曾经提供了对XA协定的反对,为了让开发人员更好的应用,以Java为例,Java提供了JTA标准,各类RM同样须要去实现JTA的相干标准接口,上面重点看看JTA标准;

JTA标准

JTA全称:Java Transaction API,Java事务API能够认为是XA标准的Java版本,为JEE平台提供了分布式事务性能,模型图如下所示:

能够发现和XA标准比拟多了一个Application Server,其实就是的web容器,常见的比方:tomcat,weblogic,jboss,websphere等;除了tomcat其余几个容器其实都实现了JTA标准,能够提供事务管理器的性能;像tomcat这种没有提供事务管理的容器能够借助第三方分布式事务管理器比方:Atomikos等;

注:JTA标准并没有指定与通信相干的接口,无关TM之间互操作性的更多细节,请参阅JTS标准;

更多:JTA文档

接口定义

Java将所有事务的标准都定义在了JTA包中,外面只有接口没有实现,能够发现此jar包最新版为1.1,2008年之后就没有更新过,想要看具体的源码间接引入即可:

<dependency>    <groupId>javax.transaction</groupId>    <artifactId>jta</artifactId>    <version>1.1</version></dependency>

具体源码如下所示,几个外围接口类用红框标出:

一共8个接口别离如下:

  1. XAResource:RM须要实现的接口,定义RM提供给TM操作的接口;
  2. Xid:事务ID;
  3. Status:事务状态,一共10个状态;
  4. Sychronization:同步接口;
  5. Transaction:事务接口;
  6. TransactionManager:事务管理器,治理事务的全生命周期
  7. TransactionSynchronizationRegistry:事务同步注册;
  8. UserTransaction:给用户应用的事务客户端,外面封装了用户能够应用事务的接口;

以上这些接口其实都不必开发者去实现,个别由RM和TM的厂商去实现:

XAResource,Xid接口:由RM厂商实现,常见的比方数据库厂商,MQ厂商等;

TransactionManager,UserTransaction接口:能够由web容器去实现如jboss,weblogic等,也能够由第三方去实现如:Atomikos等;

RM实现

常见的RM包含数据库、MQ;上面以Mysql和AcitveMQ为例子来看一下是如何应用的;

数据库

在下面的章节中咱们曾经介绍了Mysql 对XA的反对,也就是Mysq厂商曾经提供了对相干性能的反对,其实上面要做的就是驱动程序提供对Mysql XA性能的保障,同时须要实现JTA中XAResource,Xid相干接口;

com.mysql.jdbc.jdbc2.optional.MysqlXAConnection   --> XAResourcecom.mysql.jdbc.jdbc2.optional.MysqlXid            --> Xid

以上是mysql驱动程序中对JTA反对的两个外围类,具体应用也比较简单:

import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.SQLException;import javax.sql.XAConnection;import javax.transaction.xa.XAException;import javax.transaction.xa.XAResource;import javax.transaction.xa.Xid;import com.mysql.jdbc.jdbc2.optional.MysqlXAConnection;import com.mysql.jdbc.jdbc2.optional.MysqlXid;public class XAMysql {    public static void main(String[] args) throws SQLException {        // 打印XA语句用于调试        boolean logXaCommands = true;        Connection conn1 = DriverManager.getConnection("jdbc:mysql://localhost:3306/ds0", "root", "root");        XAConnection xaConn1 = new MysqlXAConnection((com.mysql.jdbc.ConnectionImpl) conn1, logXaCommands);        XAResource rm1 = xaConn1.getXAResource();        Connection conn2 = DriverManager.getConnection("jdbc:mysql://localhost:3306/ds1", "root", "root");        XAConnection xaConn2 = new MysqlXAConnection((com.mysql.jdbc.ConnectionImpl) conn2, logXaCommands);        XAResource rm2 = xaConn2.getXAResource();        // 全局事务id        byte[] gid = "global".getBytes();        int formatId = 1;        try {            // 事务分支1            byte[] bqual1 = "b1".getBytes();            Xid xid1 = new MysqlXid(gid, bqual1, formatId);            rm1.start(xid1, XAResource.TMNOFLAGS);            PreparedStatement ps1 = conn1                    .prepareStatement("insert into t_order0 (user_id,order_id) values ('110','1212')");            ps1.execute();            rm1.end(xid1, XAResource.TMSUCCESS);            // 事务分支2            byte[] bqual2 = "b2".getBytes();            Xid xid2 = new MysqlXid(gid, bqual2, formatId);            rm2.start(xid2, XAResource.TMNOFLAGS);            PreparedStatement ps2 = conn2                    .prepareStatement("insert into t_order0 (user_id,order_id) values ('111','1213')");            ps2.execute();            rm2.end(xid2, XAResource.TMSUCCESS);            // 两阶段提交            int rm1_prepare = rm1.prepare(xid1);            int rm2_prepare = rm2.prepare(xid2);            if (rm1_prepare == XAResource.XA_OK && rm2_prepare == XAResource.XA_OK) {                rm1.commit(xid1, false);                rm2.commit(xid2, false);            } else {                rm1.rollback(xid1);                rm2.rollback(xid2);            }        } catch (XAException e) {            e.printStackTrace();        }    }}

以上不仅介绍了XAResource是如何去应用的,同时也简略模仿了分布式事务管理的性能,只有在多个数据源都筹备好的状况下能力提交事务,否则回滚事务,这部分其实应该交给更加业余的组件去实现;

MQ

MQ厂商很多,不肯定每个MQ都实现了JTA的相干接口,上面要介绍的AcitveMQ实现了JTA的RM接口:

org.apache.activemq.TransactionContext      --> XAResourceorg.apache.activemq.command.XATransactionId --> Xid

上面看一个简略的应用实例:

import javax.jms.JMSException;import javax.jms.XAQueueConnection;import javax.jms.XAQueueConnectionFactory;import javax.transaction.xa.XAException;import javax.transaction.xa.XAResource;import javax.transaction.xa.Xid;import org.apache.activemq.ActiveMQXAConnectionFactory;import org.apache.activemq.ActiveMQXASession;import org.apache.activemq.TransactionContext;import org.apache.activemq.command.XATransactionId;public class MQXATest {    public static void main(String[] args) throws XAException, JMSException {        XAQueueConnectionFactory factory = new ActiveMQXAConnectionFactory("tcp://localhost:61616");        XAQueueConnection qConnection = factory.createXAQueueConnection();        qConnection.start();        ActiveMQXASession session = (ActiveMQXASession) qConnection.createXAQueueSession();        // TransactionContext实现XAResource        TransactionContext tc = session.getTransactionContext();        // XATransactionId实现Xid        Xid xid = new XATransactionId();        tc.start(xid, XAResource.TMSUCCESS);        tc.end(xid, XAResource.TMSUCCESS);        int prepare = tc.prepare(xid);        if (prepare == XAResource.XA_OK) {            tc.commit(xid, false);        } else {            tc.rollback(xid);        }    }}

以上大抵介绍了一下常见的RM厂商对JTA接口的反对,总体上分为两步:第一步厂商提供对XA接口的反对,第二步不便Java用户应用提供实现JTA接口的客户端程序(比方驱动程序,客户端jar包等);

TM实现

对于事务管理器的实现下面也说到次要包含:web容器实现、第三方实现;

web容器

这里以JBoss为例做一个简略介绍,JBoss事务相干次要在jboss-transaction和jboss-transaction-spi中,外围类次要包含:

org.jboss.tm.TxManager                                    --> TransactionManagerorg.jboss.tm.usertx.client.ServerVMClientUserTransaction  --> UserTransaction

相干配置这里就不做过多介绍,上面重点看一下第三方实现形式,以Atomikos为例;

Atomikos

Atomikos是一家公司的名字,提供了基于JTA标准的XA分布式事务TM的实现,蕴含两个产品:

  1. TransactionEssentials:开源的收费产品;
  2. ExtremeTransactions:商业版免费产品;

两个产品的关系如下图所示:

商业版本提供了更多额定的性能:

  • 反对TCC:柔性事务的反对,Try-Confirm-Cancel;
  • 反对通过RMI、IIOP、SOAP这些近程过程调用技术,进行事务流传;这其实就能够用在微服务常见的场景中:多利用多数据源的状况;

Atomikos同样提供了对UserTransaction、TransactionManager接口的实现:

com.atomikos.icatch.jta.UserTransactionImpcom.atomikos.icatch.jta.TransactionManagerImp

上面看一个简略的分布式管理器的应用:

import java.sql.Connection;import java.sql.PreparedStatement;import java.util.Properties;import javax.transaction.UserTransaction;import com.atomikos.icatch.jta.UserTransactionImp;import com.atomikos.jdbc.AtomikosDataSourceBean;public class AtomikosTest {    public static void main(String[] args) {        AtomikosDataSourceBean ds1 = createAtomikosDataSourceBean("t_order0");        AtomikosDataSourceBean ds2 = createAtomikosDataSourceBean("t_order1");        Connection conn1 = null;        Connection conn2 = null;        PreparedStatement ps1 = null;        PreparedStatement ps2 = null;        UserTransaction userTransaction = new UserTransactionImp();        try {            // 开启事务            userTransaction.begin();            // 执行分支1            conn1 = ds1.getConnection();            ps1 = conn1.prepareStatement("insert into t_order0 (user_id,order_id) values ('110','1212')");            ps1.execute();            // 执行分支2            conn2 = ds2.getConnection();            ps2 = conn2.prepareStatement("insert into t_order1 (user_id,order_id) values ('111','1213')");            ps2.execute();            // 两阶段提交            userTransaction.commit();        } catch (Exception e) {            // 异样回滚            userTransaction.rollback();        } finally {            // 敞开连贯        }    }    private static AtomikosDataSourceBean createAtomikosDataSourceBean(String dbName) {        Properties p = new Properties();        p.setProperty("url", "jdbc:mysql://localhost:3306/" + dbName);        p.setProperty("user", "root");        p.setProperty("password", "root");        AtomikosDataSourceBean ds = new AtomikosDataSourceBean();        ds.setUniqueResourceName(dbName);        // MySQL驱动XAResource实现类        ds.setXaDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");        ds.setXaProperties(p);        return ds;    }}

这里应用的RM是数据库Mysql,能够发现UserTransaction对MysqlXADataSource做了治理,进行对立的事务提交,事务回滚;比照之前XAMysql实例中手动提交每个RM,能够说更加不便简洁;

JTS标准

上文中也提到JTA标准并没有指定与通信相干的接口,无关TM之间互操作性的更多细节,须要应用JTS标准;看看官网的具体定义:

JTS规定了事务管理器的实现,事务管理器在高层反对JTA标准,在底层实现OMG对象事务服务(OTS)标准的Java映射。JTS应用CORBA OTS接口实现互操作性和可移植性(即,共传输性和可移植性)。这些接口为任何应用IIOP(internetinterorb协定)在JTS事务管理器之间生成和流传事务上下文的实现定义了一种规范机制。留神,这也容许应用IIOP传输机制上的其余API;例如,容许IIOP上的RMI。

JTS个人感觉更像是事务管理器实现上的标准,其中重点提到了反对通过RMI、IIOP、SOAP这些近程过程调用技术,进行事务流传;

更多:JTS文档

其余实现

以上重点介绍了DTP模型、XA标准,Java依据此标准定义的JTA标准,不便Java开发者应用;以及围绕这一套模型各种厂商或者一些第三方公司对其做的各种反对,实现了一种比拟通用型的分布式事务处理形式;当然下面也提到这种形式其实更偏向于CAP中的CP,是一种强一致性的实现形式,所以在面对高并发的状况下,性能是其一大缺点;越来越多的互联网公司可能更加偏向于最终一致性实现的分布式事务计划,常见的计划有:TCC,事务音讯,本地事务表等等;

TCC

TCC全称:Try,Confirm,Cancel分成三个操作:

Try:资源的预留;

Confirm:确认操作,真正的执行,相似提交;

Cancel:撤销操作,相似回滚操作;

其实能够发现和二阶段提交在流程上很像,都是先去试探,而后再提交或回滚;二者的区别:2PC更多的是面向资源(数据库,MQ等),而TCC能够面向业务层,范畴更广;另外2PC会锁定资源,而TCC能够不须要,实现最终一致性;当然TCC实现起来也更加简单,对业务的侵入也比拟大;

事务音讯

一些MQ反对事务音讯如:RocketMQ,发送的音讯和其余本地事件须要同时胜利同时失败,上面看一下它的流程:

  1. 生产者发送"待确认"音讯;
  2. RocketMQ接管到音讯进行相干保留操作,胜利当前返回状态给生产者;
  3. 生产者接管到的返回如果为SEND_OK状态,将执行本地事务操作;
  4. 依据本地事务执行的后果,生产者执行commit还是rollback;
  5. 如果第四步生产者执行操作失败,服务器会在通过固定时间段对状态为"待确认"的音讯发动回查申请;
  6. 生产者接管到回查申请后依据本地事务的后果返回commit还是rollback;
  7. 服务器收到后果后执行相干操作。

能够发现RocketMQ实现的也是最终一致性;

本地事务表

本地事务表:利用各零碎的本地事务来实现分布式事务;将大事务分成小事务来解决;

将本地的业务和音讯插入音讯表的操作放到同一个事务中,本地事务中必定是能够保障一起胜利一起失败的;

接下来能够采纳MQ由对方订阅音讯并监听,有音讯时主动触发事件;或者定时轮询扫描的形式,去查看音讯表的数据;

生产端最好保障幂等性,避免反复告诉;

一阶段

一阶段:简略了解就是如果由多个数据源操作,那么就一个一个提交,经常出现在单零碎多数据源的状况;这种模式在非凡状况下是可能呈现事务不统一的状况;spring-data-common中的ChainedTransactionManager就提供了相似的性能:链式事务;这种模式如果在一些外部零碎,网络与硬件环境个别比较稳定,硬件产生故障的概率较小,能够尝试;

Seata

阿里提供的一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简略易用的分布式事务服务;

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简略易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

这里就不过多介绍了,官网文档介绍的十分全面;

更多:Seata

总结

本文大抵对分布式事务所波及的点都做了一个简略的介绍,能够把它当作一个纲要性的货色去看,外面很多点只有在真正应用的时候能力发现一些其中的问题;分布式事务能够说是所有技术中的一个难点,解决的计划也很多,这个须要依据业务的理论状况,做出最合适的抉择,这个过程其实也是挺难的,你须要理解每种计划它的优缺点,它实用的范畴,没有一个万能的计划。

感激关注

能够关注微信公众号「回滚吧代码」,第一工夫浏览,文章继续更新;专一Java源码、架构、算法和面试。