Easily complete a distributed transaction TCC, nanny level tutorial with PHP

Time:2021-10-25

What is TCC? TCC is the abbreviation of try, confirm and cancel. It was first proposed by a paper entitled life beyond distributed transactions: an apostate’s opinion published by Pat helland in 2007.

TCC composition

TCC is divided into three stages

  • Try phase: try to execute, complete all business checks (consistency), and reserve necessary business resources (quasi isolation)
  • Confirm phase: if the try of all branches is successful, go to the confirm phase. Confirm really executes the business without any business check, and only uses the business resources reserved in the try phase
  • Cancel phase: if one try of all branches fails, go to the cancel phase. Cancel releases the business resources reserved in the try phase.

There are three roles in TCC distributed transactions, which are the same as the classic XA distributed transactions:

  • The AP / application initiates a global transaction and defines which transaction branches are included in the global transaction
  • RM / resource manager is responsible for the management of various resources in branch transactions
  • TM / transaction manager is responsible for coordinating the correct execution of global transactions, including the execution of confirm and cancel, and handling network exceptions

If we want to conduct a business similar to inter-bank transfer, the transfer out and transfer in are in different micro services respectively. The typical sequence diagram of a successfully completed TCC transaction is as follows:

Easily complete a distributed transaction TCC, nanny level tutorial with PHP

TCC practice

Let’s develop a TCC transaction

At present, the open source framework available for TCC is mainly Java language, with Seata as the representative. Our example uses nodejs and the distributed transaction framework is DTM, which supports distributed transactions very gracefully. Let’s explain the composition of TCC in detail

Let’s write a specific try / confirm / cancel processing function

$vega->handleFunc('/api/TransOutTry', function (Mix\Vega\Context $ctx) {
    var_dump('TransOutTry', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);
})->methods('POST');
$vega->handleFunc('/api/TransOutConfirm', function (Mix\Vega\Context $ctx) {
    var_dump('TransOutConfirm', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);
})->methods('POST');
$vega->handleFunc('/api/TransOutCancel', function (Mix\Vega\Context $ctx) {
    var_dump('TransOutCancel', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);
})->methods('POST');

$vega->handleFunc('/api/TransInTry', function (Mix\Vega\Context $ctx) {
    var_dump('TransInTry', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);
})->methods('POST');
$vega->handleFunc('/api/TransInConfirm', function (Mix\Vega\Context $ctx) {
    var_dump('TransInConfirm', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);
})->methods('POST');
$vega->handleFunc('/api/TransInCancel', function (Mix\Vega\Context $ctx) {
    var_dump('TransInCancel', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);
})->methods('POST');

At this point, the processing functions of each sub transaction are OK, and then start the TCC transaction for branch calls

    Dtmcli\tccGlobalTransaction($dtm, function ($tcc) use ($svc) {
        /** @var Dtmcli\Tcc $tcc */
        $req = ['amount' => 30];
        $tcc->callBranch($req, $svc . '/TransOutTry', $svc . '/TransOutConfirm', $svc . '/TransOutCancel');
        $tcc->callBranch($req, $svc . '/TransInTry', $svc . '/TransInConfirm', $svc . '/TransInCancel');
    });

So far, a complete TCC distributed transaction is written.

If you want to run a successful example completely, refer to the example yedf / dtmcli PHP sample, which is very simple to run

#Deploy start DTM
#Docker version 18 or above is required
git clone https://github.com/yedf/dtm
cd dtm
docker-compose up

#Start another command line
https://github.com/yedf/dtmcli-php-sample.git
cd dtmcli-php-sample
composer install
php demo.php start

Rollback of TCC

What if the bank finds that the account of user 2 is abnormal and fails to return when it is ready to transfer the amount to user 2? We can simulate this by having transin return a failure

$vega->handleFunc('/api/TransInTry', function (Mix\Vega\Context $ctx) {
    var_dump('TransInTry', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'FAILURE']);
})->methods('POST');

We give the sequence diagram of transaction failure interaction

Easily complete a distributed transaction TCC, nanny level tutorial with PHP

The difference between this and a successful TCC is that when a sub transaction returns a failure, the global transaction is subsequently rolled back and the cancel operation of each sub transaction is called to ensure that all global transactions are rolled back.

In the TCC transaction mode, many readers will ask, what happens if confirm / cancel fails? This is a good question, which means that you are thinking deeply about the TCC transaction mode. The first case is temporary failure, such as network failure, application or database downtime. Retry such errors and finally return success; The other case is business failure. According to the TCC agreement, resources are locked in the first stage to ensure that sufficient resources can be used for confirm / cancel execution. In other words, in program logic, confirm / cancel is not allowed to return business failure. If a business failure occurs, it is a bug and needs to be manually repaired by the developer.

Summary

In this article, we introduce the theoretical knowledge of TCC, and give a complete process of writing a TCC transaction through an example, including normal successful completion and successful rollback. I believe readers have a deep understanding of TCC through this article.

For more comprehensive knowledge of distributed transactions, please refer toSeven classic solutions for distributed transactions

The examples used in this paper are excerpts fromyedf/dtm, it supports a variety of transaction modes: TCC, Saga, Xa, transaction message cross language support, and supports clients in golang, python, Java, PHP, nodejs and other languages. Refer toSDKs for each language。 It provides sub transaction barrier function to gracefully solve idempotent, suspension, null compensation and other problems.

After reading this article, welcome to visitgithub.com/yedf/dtmProject, give star support!

This work adoptsCC agreement, reprint must indicate the author and the link to this article

Recommended Today

Swift advanced (XV) extension

The extension in swift is somewhat similar to the category in OC Extension can beenumeration、structural morphology、class、agreementAdd new features□ you can add methods, calculation attributes, subscripts, (convenient) initializers, nested types, protocols, etc What extensions can’t do:□ original functions cannot be overwritten□ you cannot add storage attributes or add attribute observers to existing attributes□ cannot add parent […]