What is TCC? TCC is the abbreviation of Try, Confirm and Cancel. It was first proposed by Pat Helland in a paper entitled "Life beyond Distributed Transactions: an Apostate's Opinion" published in 2007.

TCC composition

TCC is divided into 3 stages

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

In TCC distributed transaction, there are 3 roles, the same as the classic XA distributed transaction:

  • AP/application, initiate a global transaction, define which transaction branches the global transaction contains
  • RM/resource manager, responsible for the management of various resources of branch affairs
  • TM/transaction manager, 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 bank inter-bank transfer, the transfer out (TransOut) and transfer in (TransIn) are in different microservices. A typical sequence diagram of a successfully completed TCC transaction is as follows:

image.png

TCC network abnormal

In the process of TCC's entire global transaction, various network abnormalities may occur. Typical examples are empty rollback, idempotence, and suspension. Due to TCC's abnormal conditions, it is similar to SAGA, reliable messages and other transaction patterns, so we Put all the abnormal solutions in this article "Seven Classic Solutions for Distributed Transactions" to explain the sub-transaction barrier link

TCC practice

Below we carry out the specific development of a TCC transaction

The open source framework currently available for TCC is mainly the Java language, with seata being the representative. Our example uses nodejs, the distributed transaction framework used is dtm, and its support for distributed transactions is very elegant. Let's explain the composition of TCC in detail below

Let's write a specific Try/Confirm/Cancel processing function

router.post('/api/TransOutTry', (ctx, next) => {
  console.log("TransOutTry")
  ctx.body = { result: "SUCCESS" }
}).post('/api/TransOutConfirm', (ctx, next) => {
  console.log("TransOutConfirm")
  ctx.body = { result: "SUCCESS" }
}).post('/api/TransOutCancel', (ctx, next) => {
  console.log("TransOutCancel")
  ctx.body = { result: "SUCCESS" }
}).post('/api/TransInTry', (ctx, next) => {
  console.log("TransInTry")
  ctx.body = { result: "SUCCESS" }
}).post('/api/TransInConfirm', (ctx, next) => {
  console.log("TransInConfirm")
  ctx.body = { result: "SUCCESS" }
}).post('/api/TransInCancel', (ctx, next) => {
  console.log("TransInCancel")
  ctx.body = { result: "SUCCESS" }
})

At this point, the processing function of each sub-transaction has been OK, and then the TCC transaction is opened, and the branch call is made

async function FireTcc() {
  let dtm = "http://localhost:8080/api/dtmsvr" // dtm服务地址
  let svc = "http://localhost:4005/api" // 本地服务前缀
  // 开启一个tcc事务,第二个参数里面,写全局事务的逻辑
  await dtmcli.tccGlobalTransaction(dtm, async (t) => {
    let req = { amount: 30 } // 子事务需要的负荷
    console.log("calling trans out")
    // 注册事务分支,并调用分支中的Try
    await t.callBranch(req, svc + "/TransOutTry", svc + "/TransOutConfirm", svc + "/TransOutCancel")
    console.log("calling trans in")
    // 注册事务分支,并调用分支中的Try
    await t.callBranch(req, svc + "/TransInTry", svc + "/TransInConfirm", svc + "/TransInCancel")
  })
}

At this point, a complete TCC distributed transaction has been written.

If you want to run a successful sample completely, then refer to this example yedf/dtmcli-node-sample, it is very simple to run it

# 部署启动dtm
# 需要docker版本18以上
git clone https://github.com/yedf/dtm
cd dtm
docker-compose up

# 另起一个命令行
git clone https://github.com/yedf/dtmcli-node-sample
cd dtmcli-node-sample
npm install
node .

TCC rollback

What happens if the bank finds that the account of User 2 is abnormal when it is about to transfer the amount to User 2 and the return fails? We give a sequence diagram of transaction failure interaction

image.png

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

summary

In this article, we introduced the theoretical knowledge of TCC, and through an example, gave a complete process of writing a TCC transaction, covering the normal successful completion and successful rollback. I believe that readers have an in-depth understanding of TCC through this article.

For more comprehensive knowledge of distributed transactions, please refer to "Seven Classic Solutions for Distributed Transactions"

The examples used in the article are excerpted from yedf/dtm , which supports multiple transaction modes: TCC, SAGA, XA, transaction message cross-language support, and supports clients in languages such as golang, python, Java, PHP, nodejs, etc., refer to each of Language SDK . Provide sub-transaction barrier function, elegantly solve the problems of idempotence, suspension, null compensation and so on.

After reading this dry goods, welcome everyone to visit the https://github.com/yedf/dtm project, give star support!


叶东富
1.1k 声望6.1k 粉丝