What is a distributed transaction? The inter-bank transfer service is A typical distributed transaction scenario. Suppose A needs to transfer the data of two banks to B, and the ACID of the transfer cannot be guaranteed through the local transaction of one database, but can only be solved through distributed transaction.

Distributed transaction means that the transaction initiator, resource and resource manager and transaction coordinator are located on different nodes of the distributed system. User A-100 and user B+100 are not on the same node. Essentially, distributed transactions are about ensuring that data operations are performed correctly in a distributed scenario.

What is a TCC distributed transaction? TCC stands for Try, Confirm, Cancel. It was first proposed by Pat Helland in a paper titled Life Beyond Distributed Transactions: An Apostate’s Opinion published in 2007.

Of TCC

TCC is divided into three phases

  • Try phase: Attempts to execute, completes all service checks (consistency), and reserves required service resources (quasi-isolation).
  • Confirm phase: If all branch tries are successful, the Confirm phase is entered. Confirm Indicates that services are actually executed without any service check. Service resources reserved in the Try phase are used
  • Cancel phase: If one of the tries for all branches fails, the Cancel phase is entered. Cancel Releases service resources reserved in the Try phase.

In TCC distributed transactions, there are three roles, as in classic XA distributed transactions:

  • AP/ application, initiates a global transaction, and defines which transaction branches the global transaction contains
  • RM/ Resource manager, responsible for the management of branch transaction resources
  • TM/ transaction manager, responsible for coordinating the correct execution of global transactions, including Confirm, Cancel, and handling network exceptions

If we were to perform a business similar to an inter-bank transfer, with a TransOut and a TransIn in different microservices, the typical sequence diagram for a successfully completed TCC transaction is as follows:

TCC practice

Let’s proceed to the specific development of a TCC transaction

The main open source frameworks available for TCC are the Java language, represented by SEATA. Our example uses Python and DTM, a distributed transaction framework with elegant support for distributed transactions. Let’s look at the TCC in more detail

Let’s write a specific Try/Confirm/Cancel handler

@app.post("/api/TransOutTry")
def trans_out_try() :
    return {"dtm_result": "SUCCESS"}

@app.post("/api/TransOutConfirm")
def trans_out_confirm() :
    return {"dtm_result": "SUCCESS"}

@app.post("/api/TransOutCancel")
def trans_out_cancel() :
    return {"dtm_result": "SUCCESS"}

@app.post("/api/TransInTry")
def trans_in_try() :
    return {"dtm_result": "SUCCESS"}

@app.post("/api/TransInConfirm")
def trans_in_confirm() :
    return {"dtm_result": "SUCCESS"}

@app.post("/api/TransInCancel")
def trans_in_cancel() :
    return {"dtm_result": "SUCCESS"}
Copy the code

At this point, the handling function of each subtransaction is OK, then the TCC transaction is opened and the branch call is made

This is the DTM service address
dtm = "http://localhost:8080/api/dtmsvr"
# This is the business microservice address
svc = "http://localhost:5000/api"

@app.get("/api/fireTcc")
def fire_tcc() :
    # Initiates a TCC transaction in which tCC_trans performs the specific business processing
    gid = tcc.tcc_global_transaction(dtm, tcc_trans)
    return {"gid": gid}

# TCC transaction specific processing
def tcc_trans(t) :
    req = {"amount": 30} # Load of business requests
    Try # call out services | Confirm | Cancel
    t.call_branch(req, svc + "/TransOutTry", svc + "/TransOutConfirm", svc + "/TransOutCancel")
    # call into the service of the Try | Confirm | Cancel
    t.call_branch(req, svc + "/TransInTry", svc + "/TransInConfirm", svc + "/TransInCancel")
Copy the code

At this point, a complete TCC distributed transaction is written.

If you want to run a complete successful example, refer to the example yedf/dtmcli-py-sample, which is very simple to run

# Deploy to 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
git clone https://github.com/yedf/dtmcli-py-sample
cd dtmcli-py-sample
pip3 install flask dtmcli requests
flask run

# Start another command line
curl localhost:5000/api/fireTcc
Copy the code

TCC rolled back

What if when the bank is preparing to transfer the amount to user 2, it finds that the account of user 2 is abnormal and fails to return?

Let’s change the previous TransIn handler to return failure, and the entire transaction will eventually fail to be rolled back

@app.post("/api/TransInTry")
def trans_in_try() :
    return {"dtm_result": "FAILURE"}
Copy the code

We present a sequence diagram of a transaction failure interaction

The difference between this and successful TCC is that when a subtransaction returns a failure, the global transaction is subsequently rolled back, calling Cancel for each subtransaction to ensure that all global transactions are rolled back.

The TCC network is abnormal

During the entire process of global transactions, TCC may have various network exceptions, typically null-rollback, idempotences, and suspension. Since the exceptions of TCC are similar to the transaction patterns such as SAGA and reliable messaging, we put all the solutions to these exceptions in the article “Subtransaction Barriers, A function call to solve distributed transaction disorder

summary

In this article, we introduce the theory of TCC and, with an example, complete the process of writing a TCC transaction, covering both normal successful completion and successful rollback. I believe that readers have a deep understanding of TCC through this article.

For a more comprehensive knowledge of distributed transactions, please refer to the seven classic solutions for distributed transactions

After reading this article, welcome to visit yeDF/DTM project, give a star support!

DTM supports a variety of languages, including GO, Python, PHP, and Node. You can access each language client and sample