Use Go to easily complete a SAGA distributed transaction, nanny level tutorial

Inter bank transfer business is A typical distributed transaction scenario. Assuming that A needs inter-bank transfer to B, the data of two banks are involved. The ACID of transfer cannot be guaranteed through the local transaction of one database, but can only be solved through distributed transactions.

Distributed transaction

Distributed transaction in the distributed environment, in order to meet the needs of availability, performance and degraded services and reduce the requirements of consistency and isolation, on the one hand, it follows the BASE theory:

  • Basic Availability
  • Soft state
  • Final consistency

On the other hand, distributed transactions also partially follow the ACID specification:

  • Atomicity: strictly follow
  • Consistency: the consistency after the transaction is completed is strictly followed; Consistency in transactions can be relaxed appropriately
  • Isolation: parallel transactions cannot be affected; Visibility of transaction intermediate results allows security relaxation
  • Persistence: strictly follow

SAGA

Saga is a distributed transaction scheme mentioned in this database paper SAGAS. Its core idea is to split long transactions into multiple local short transactions, which are coordinated by saga transaction coordinator. If each local transaction is completed successfully, it will be completed normally. If a step fails, the compensation operation will be called at one time according to the reverse order.

At present, the open source framework available for SAGA is mainly Java language, with seata as the representative.

The composition of SAGA is explained in detail below:

In the DTM transaction framework, there are three roles, which are the same as the classic XA distributed transaction:

  • 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 SAGA forward / reverse operations

SAGA practice

For the example of bank transfer we want to make, we will carry out transfer in and transfer out in the forward operation, and make the opposite adjustment in the compensation operation.

First, we create an account balance table:

CREATE TABLE dtm_busi.`user_account` (
  `id` int(11) AUTO_INCREMENT PRIMARY KEY,
  `user_id` int(11) not NULL UNIQUE ,
  `balance` decimal(10,2) NOT NULL DEFAULT '0.00',
  `create_time` datetime DEFAULT now(),
  `update_time` datetime DEFAULT now()
);

We first write the core business code to adjust the user's account balance

func qsAdjustBalance(uid int, amount int) (interface{}, error) {
    _, err := dtmcli.SdbExec(sdbGet(), "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
    return dtmcli.ResultSuccess, err
}

Let's write the specific processing function of forward operation / compensation operation

    app.POST(qsBusiAPI+"/TransIn", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
        return qsAdjustBalance(2, 30)
    }))
    app.POST(qsBusiAPI+"/TransInCompensate", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
        return qsAdjustBalance(2, -30)
    }))
    app.POST(qsBusiAPI+"/TransOut", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
        return qsAdjustBalance(1, -30)
    }))
    app.POST(qsBusiAPI+"/TransOutCompensate", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
        return qsAdjustBalance(1, 30)
    }))

At this point, the processing function of each sub transaction is OK, and then start SAGA transaction to make branch calls

    req := &gin.H{"amount": 30} // Microservice load
    // DtmServer is the address of DTM service
    saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
        // Add a TransOut sub transaction. The forward operation is url: qsBusi+"/TransOut", and the reverse operation is url: qsBusi+"/TransOutCompensate"
        Add(qsBusi+"/TransOut", qsBusi+"/TransOutCompensate", req).
        // Add a sub transaction of TransIn. The forward operation is url: qsBusi+"/TransOut", and the reverse operation is url: qsBusi+"/TransInCompensate"
        Add(qsBusi+"/TransIn", qsBusi+"/TransInCompensate", req)
    // When saga transaction is committed, dtm will complete all sub transactions / roll back all sub transactions
    err := saga.Submit()

So far, a complete SAGA distributed transaction is written.

If you want to run a successful example completely, after setting up the environment according to the instructions of the yedf/dtm project, run the saga example through the following command:

go run app/main.go quick_start

If you want to develop small programs or app s, you can help you realize your development needs through a third-party professional development platform: Xiamen cares about technology -Focus on applet development Xiamen app customization development . website development

Keywords: Go Database MySQL

Added by todding01 on Tue, 21 Dec 2021 14:21:24 +0200