×
Community Blog Understand the XA Mode of Distributed Transaction in Six Figures

Understand the XA Mode of Distributed Transaction in Six Figures

This article gives a thorough explanation of Seata XA mode.

1

By Zhu Jinjun

XA protocol is a distributed transaction processing specification proposed by the X/Open organization. It mainly defines the interface between the transaction manager (TM) and the local resource manager (RM). Currently, mainstream databases (such as Oracle and DB2) all support the XA protocol.

Since MySQL 5.0, its InnoDB storage engine has supported the XA protocol. In this article, the MySQL database is used as the experiment environment to introduce the source code.

Two-Phase Commit

For a distributed transaction, the two-phase commit process is divided into prepare and commit phases. Let’s take the e-commerce system as an example. The distributed system has three services: order, account, and inventory, as shown in the following figure:

2

In the first phase, the transaction coordinator sends a prepare request to a transaction participant. The transaction participant will reply yes if it can commit the transaction on receiving the request or no if it cannot.

In the second phase, if all transaction participants reply yes, the transaction coordinator will send a commit request to all transaction participants. Otherwise, a rollback request is sent.

There are three problems with the two-phase commit:

  • Synchronous Blocking – Resources are locked for local transaction in the prepare phase. Transactions must wait until the previous one is completed if they need to modify the account. This declines the system performance.
  • Single Point Failure at the Coordinator – For example, the processing is down after the first prepare phase completes and before the coordinator sends the commit command in the second phase. The data resources of all services will be locked, and the transaction will wait indefinitely.
  • Data Inconsistency – If the first prepare phase completes, but the coordinator in the second phase fails to send a commit command, the data will be inconsistent.

Three-Phase Commit

The three-phase commit makes improvements to solve the problems of two-phase commit:

  • A timeout mechanism is introduced to the coordinator and the transaction participant.
  • The first prepare phase is divided into two steps: canCommit and preCommit.

The following figure shows how it works:

3

The preCommit phase introduced enables the coordinator to check the status of each transaction participant for a second time before the commit to ensure the status consistency. However, the problem here is that if a rollback request is sent in the third phase, but some nodes do not receive it, these nodes will submit the transaction after timeout, resulting in data inconsistency.

XA Transaction Syntax

The XA transaction syntax is listed below:

In the first phase: start the XA transaction. In this phase, xid indicates the global transaction ID:

XA {START|BEGIN} xid [JOIN|RESUME]

End the XA transaction:

XA END xid [SUSPEND [FOR MIGRATE]]

The second phase is the prepare phase:

XA PREPARE xid

The third phase is the commit/rollback phase:

XA COMMIT xid [ONE PHASE]
XA ROLLBACK xid

View all transactions in the PREPARE phase:

XA RECOVER XA RECOVER [CONVERT XID]

Introduction to Seata XA

Seata is an open-source distributed transaction solution released by Alibaba. Currently, Seata supports four transaction modes: AT, TCC, SAGA, and XA.

Seata XA mode is implemented using database support for the XA protocol in branch transactions. Let's take a look at the Seata official website: [1]

4

As shown in the figure above, the process of Seata XA mode is the same as that of other modes:

  1. TM starts the global transaction.
  2. RM registers the branch transaction with TC.
  3. RM reports the branch transaction status to TC.
  4. TC sends a commit/rollback Request to RM.
  5. TM ends the global transaction.

Here is an introduction to the UML class diagram associated with RM client initialization: [2]

5

In this figure, there’s an AbstractNettyRemotingClient class. Its internal class ClientHandler processes requests from TC and delegates them to the processMessage method of the parent class AbstractNettyRemoting. The processMessage method calls the process method of the RmBranchCommitProcessor class.

Note: The Seata XA mode optimizes traditional three-phase commit and changes to two-phase commit:

  • The first phase performs three steps of XA start, SQL execution, and XA end. Then, it enters the XA prepare phase directly.
  • The second phase executes XA commit/rollback requests.

MySQL currently supports this two-phase optimization of the Seata XA mode.

However, this optimization is not supported by Oracle because Oracle implements the standard XA protocol. In other words, the coordinator sends a prepare request to the transaction participants after the XA end. Then, it sends the commit/rollback request. Thus, Seata XA mode is not supported by Oracle.

Seata XA Source Code

The Seata XA mode is implemented using a data source proxy. The data source proxy must be configured manually. The code is listed below:

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
    return new DruidDataSource();
}

@Bean("dataSourceProxy")
public DataSource dataSource(DruidDataSource druidDataSource) {
    return new DataSourceProxyXA(druidDataSource);
}
  • Users can also create an XAConnection based on a common DataSource. However, this method may incur compatibility issues with other databases such as Oracle. Therefore, Seata allows developers to configure an XADataSource by themselves.
  • The XA data source proxy provided by Seata requires the Druid connection pool in the code framework.

1. Phase I of XA

When RM receives the DML request, Seata will use ExecuteTemplateXA for execution. The key of the execute method is to change the autocommit attribute to false, which is true for MySQL by default. After committing the transaction, the autocommit attribute needs to be changed back.

The following part describes the main code during the first-phase commit of XA.

1) Enable XA

The [1] mark in the code above calls the setAutoCommit method of the ConnectionProxyXA class. In the source code of this method, XA start does three things:

  • Registers a branch transaction with TC
  • Calls the XA Start of the data source

xaResource.start(this.xaBranchXid, XAResource.TMNOFLAGS);

  • Set xaActive to true

RM does not directly use the branchId returned by TC as the branchId of the XA data source but uses the global transaction ID (xid) and branchId to rebuild one.

2) Execute SQL

Call the execute method of PreparedStatementProxyXA to execute the SQL statement

3) XA end/prepare

public void commit() throws SQLException {
    // Part of the source code is omitted
    try {
        // XA End: Success
        xaResource.end(xaBranchXid, XAResource.TMSUCCESS);
        // XA Prepare
        xaResource.prepare(xaBranchXid);
        // Keep the Connection if necessary
        keepIfNecessary();
    } catch (XAException xe) {
        try {
            // Branch Report to TC: Failed
            DefaultResourceManager.get().branchReport(BranchType.XA, xid, xaBranchXid.getBranchId(),
                BranchStatus.PhaseOne_Failed, null);
        } catch (TransactionException te) {
            // Only a warn-level log is printed
        }
        throw new SQLException(
            "Failed to end(TMSUCCESS)/prepare xa branch on " + xid + "-" + xaBranchXid.getBranchId() + " since " + xe
                .getMessage(), xe);
    } finally {
        cleanXABranchContext();
    }
}

This source code tells us that the commit statement does three things:

  • Calls the XA end of the data source
  • Calls the XA prepare of the data source
  • Reports branch transaction status to TC

As we’ve discussed, Seata combines the first two phases of the XA protocol into one.

2. XA Commit

The call relationship is listed on the following sequence diagram:

6

Let’s take a look at the process method of the RmBranchCommitProcessor class. The code is listed below:

@Override
public void process(ChannelHandlerContext ctx, RpcMessage rpcMessage) throws Exception {
    String remoteAddress = NetUtil.toStringAddress(ctx.channel().remoteAddress());
    Object msg = rpcMessage.getBody();
    if (LOGGER.isInfoEnabled()) {
        LOGGER.info("rm client handle branch commit process:" + msg);
    }
    handleBranchCommit(rpcMessage, remoteAddress, (BranchCommitRequest) msg);
}

As shown in the sequence diagram, this handleBranchCommit method finally calls the handle method of AbstractRMHandler and calls the finishBranch method of the ResourceManagerXA class using the branchCommit method.

The ResourceManagerXA class is a resource manager of XA mode. The following figure shows the UML classes of the resource manager (RM) in Seata:

7

This finishBranch method calls the connectionProxyXA.xaCommit method. Let's take a look at the xaCommit method:

public void xaCommit(String xid, long branchId, String applicationData) throws XAException {
    XAXid xaXid = XAXidBuilder.build(xid, branchId);
 // Here, xaResource is MysqlXAConnection as MySQL is used.
    xaResource.commit(xaXid, false);
    releaseIfNecessary();
}

The commit method of the data source is called to commit the RM branch transaction.

At this point, the entire RM branch transaction has ended. The Rollback code logic is similar to that of commit.

This xaResource is an instance of the MysqlXAConnection class in the mysql-connector-java.jar packet. It encapsulates the XA protocol interface provided by MySQL.

Summary

Seata XA mode is implemented using the data source proxy. The underlying layer uses the native support of the database for the XA protocol.

In the Java driver library of MySQL, the MysqlXAConnection class encapsulates the underlying API of the XA protocol for external calls.

TCC and SAGA modes need to implement prepare, commit, and rollback logic in the business code. Compared with that, XA mode does not intrude into the business code.

References

[1] http://seata.io/en-us/docs/overview/what-is-seata.html
[2] https://github.com/seata/seata

0 0 0
Share on

You may also like

Comments

Related Products