×
Community Blog Design and Implementation of Seata-go TCC

Design and Implementation of Seata-go TCC

This article introduces the design idea, exception handling, and practical use of TCC in Seata-go.

By Yuecai Liu

Seata is an open-source distributed transaction solution that provides high-performance and easy-to-use distributed transaction services for modern microservices architectures. Seata offers various transaction modes, including AT, TCC, SAGA, and XA, to help users solve business problems in different scenarios. Seata also supports multi-language programming and provides a simple API interface, extensive documentation, and quick-start samples projects to help developers get started with Seata quickly.

Seata-go is the Golang implementation of Seata's multilingual ecosystem, designed to help Golang developers use Seata's capabilities to solve distributed transaction problems. Seata-go reuses Seata TC's capabilities and client functionalities to retain the same functionality as Seata.

This article mainly introduces the design and use of TCC mode in Seata-go, covering the following topics:

• Seata-go TCC Realization Principle
• Seata-go TCC Exception Handling
• Seata-go Outlook

Seata-go TCC Realization Principle

Seata-go uses getty for TCP network communication and fully implements Seata's communication protocol. The lower layers implement the configuration and registry centers and support the integration of many third-party frameworks, such as Dubbo, grpc, and gorm. Currently, Seata-go is actively communicating with various communities to support the integration of more frameworks. The simplified system architecture diagram of Seata-go is shown below.

1

Before introducing TCC mode in Seata-go, let's briefly review its meaning. TCC is an implementation of a distributed transaction solution that uses a two-phase commit protocol. Its full name is Try-Confirm-Cancel. Try is the reserved resource operation, Confirm is the commit operation, and Cancel is the rollback operation. In the first phase of TCC, all sub-transactions first trigger the Try operation. If all sub-transactions are successful in phase one, all sub-transactions are triggered to perform the Confirm operation in phase two. Otherwise, the Cancel operation is performed in phase two to ensure the status consistency of each sub-transaction.

TCC is an intrusive distributed transaction solution. Users must implement the logic of the Try, Confirm, and Cancel phases by themselves. This means more code and greater intrusion into the business. The advantage is that it is more flexible and can be used to solve the problems of more complex distributed transaction scenarios.

Before introducing the TCC mode of Seata-go, let's review three core roles of Seata: TC, TM, and RM. TC is the transaction coordinator, responsible for maintaining the state of the global transaction and triggering the commit and rollback of branch transactions. TM is the transaction manager, responsible for the orchestration of sub-transactions and the commit and rollback of global transactions. RM is the resource manager that manages resources for branch transaction processing, such as MySQL database operations.

With a basic understanding of these roles, we can roughly understand the transaction process of TCC. It involves the following steps:

• TM sends requests to TC to start a global transaction. TC records the status of the global transaction.
• TM sends requests to all RMs. RMs register the branch transaction with TC and then execute the logic of the Try phase.
• If one of the RMs returns an execution failure in the Try phase to TM, TM sends a "roll back the global transaction" request to TC. After TC receives the request, it sends a Rollback command to all the RMs that have executed the Try operation, triggering RMs to execute the Cancel logic.
• If all RMs return execution successes in the Try phase to TM, TM sends a "commit global transaction" request to TC. After TC receives the request, it sends a Commit command to all the RMs that have executed the Try operation, triggering RMs to execute the Commit logic.

At this point, a complete distributed transaction is executed. The flowchart below shows the process.

2

In Seata-go, to provide convenience to users, two methods for defining TCC services are provided. One is to implement the TwoPhaseInterface interface and the details are as follows.

3
The other is to define TCC services by tag. This method is more complicated but more flexible.

4

The second method is mainly designed to meet some special scenarios. For example, the server and client of dubbo-go are defined by the tag. At this time, TCC services need to be defined by the tag. In general, we recommend that you use the first method of inheriting the interface because it is simpler.

During actual usage, users only need to perform the following operations:

• Define your TCC service, and you can refer to either of the two methods mentioned above.
• Call TCC's proxy method NewTCCServiceProxy to encapsulate the TCC service into a proxy.
• Orchestrate your sub-transactions and pass them to the WithGlobalTx method of the distributed transaction.

Here's an example screenshot, but for more detailed samples, please refer to the seata-go-samples project at https://github.com/seata/seata-go-samples

5

Seata-go TCC Exception Handling

In the practical use of TCC, issues such as network latency or execution time of business code logic may arise, resulting in the following problems:.

Idempotence: In the first and second phases of a transaction, if the RM fails to respond to the TC or TM in time due to network latency or other factors, it may repeatedly trigger the execution of the logic of the first and second phases. As a result, it becomes necessary to consider the idempotence of the business logic.

Empty rollback: Due to network latency or other reasons, RM receives a Rollback request before receiving a Try request, resulting in an empty rollback.

Suspension: Due to network latency or other factors, the RM may receive a Rollback request before the Try request and, after processing the Rollback request, may receive the Try request. At this point, the global transaction ends, and the resources reserved by the transaction remain unreleased.

In Seata-go, two solutions are provided to help users address these problems.

The principle of the first method is the same as the processing logic of Seata Java, which is implemented with the help of the tcc_fence_log transaction state table.

6

Users need to create this table in their business database. When RM submits business SQL statements, it will insert a record into this table at the same time. These two SQL statements are completed in a local transaction. In this table, "global transaction ID + branch transaction ID" is a joint primary key. As a result, repeated execution fails. This solves the idempotence problem in the Try phase. During the Commit and Cancel phases, the status of branch transactions in this table is queried before the actual logic is performed. Finally, the status is updated. This ensures the idempotence of the Commit and Cancel phases.

Let's look at how Seata-go solves transaction suspension and empty rollback. If a Rollback request comes, RM queries the tcc_fence_log table and finds that there is no record (because RM has not received the Try request). At this time, it will insert a record into the tcc_fence_log table, mark the status as suspend, and then exit directly without executing the logic of Rollback, thus avoiding the problem of empty rollback. If RM receives another Try request later, the SQL transaction cannot be committed and fails because the tcc_fence_log table already has a record (it will have a primary key conflict). This prevents the issue of suspension.

To implement this method, you need to use the proxy data source provided by Seata-go. These operations will be completed by the proxy data source. Users only need to turn on the switch and pay attention to their business SQL.

The second method is implemented manually by the user. The principle is similar to the first method, but the operation logic of tcc_fence_log needs to be implemented by the users themselves. The following screenshot shows the general usage. For more details, please refer to this sample code: https://github.com/seata/seata-go-samples/tree/main/tcc/fence

7

Outlook

The Seata-go community has recently collaborated with many domestic Go language microservice frameworks and development communities behind ORM frameworks. For instance, the GORM framework has been integrated into Sample, and more ORM frameworks will be integrated into Seata-go-Samples projects in the future. Collaboration with the MOSN community is currently in progress to enable a true Seata-based Transaction Mesh.

The XA mode of Seata-go will be released in May, after which Seata-go will support TCC, XA, and AT transaction modes. The focus of Seata-go will shift to the feature development of Saga mode.

Currently, the Saga mode only implements the forward push and reverse rollback capabilities of service orchestration. To improve the user experience on the Seata platform, further service orchestration can implement functions such as DAG, scheduled tasks, and batch task scheduling, covering all workflow processes. At present, Seata-go relies on the TC of Seata Java. According to the work plan, future versions of Seata-go may need to implement a more powerful TC scheduling.

The Seata-go community is growing rapidly, and we invite interested individuals to join us and help Seata-go grow together!

0 1 0
Share on

You may also like

Comments