Go-zero Support

dtm has collaborated deeply with go-zero to create a go-zero native support solution for distributed transactions, providing a minimalist user experience. Thanks to go-zero author kevwan for his support

Dtm supports the go-zero microservices framework natively from v1.6.0 onwards. go-zero version requires v1.2.4 or higher

Run An Existing Example

Let's run an example of go-zero using etcd as a registry service centre as follows.

  • Start etcd
# Prerequisite: etcd is installed
  • Configure dtm
  Driver: 'dtm-driver-gozero' # Configure dtm to use go-zero's microservice protocol
  Target: 'etcd://localhost:2379/dtmservice' # Register dtm to this address in etcd
  EndPoint: 'localhost:36790' # local address for dtm
  • Start dtm
# Prerequisite: conf.yml properly configured
go run app/main.go -c conf.yml
  • Run a go-zero service
git clone https://github.com/dtm-labs/dtmdriver-clients && cd dtmdriver-clients
cd gozero/trans && go run trans.go
  • Initiate a go-zero transaction using dtm
# In the directory of dtmdriver-clients
cd gozero/app && go run main.go

When you see the log of gozero/trans:

2021/12/03 15:44:05 transfer out 30 cents from 1
2021/12/03 15:44:05 transfer in 30 cents to 2

The transaction completed properly

Development Access

Refer to the code in dtm-labs/dtmdriver-clients

// The following line imports gozero's dtm driver
import _ "github.com/dtm-labs/driver-gozero"

// dtm has been registered to the following address via the previous configuration, so use that address in dtmgrpc
var dtmServer = "etcd://localhost:2379/dtmservice"

// Load the configuration from the config file below and then get the address of the business service via BuildTarget
var c zrpc.RpcClientConf
conf.MustLoad(*configFile, &c)
busiServer, err := c.BuildTarget()

  // Use dtmgrpc to generate a message-based distributed transaction and commit it
	gid := dtmgrpc.MustGenGid(dtmServer)
	msg := dtmgrpc.NewMsgGrpc(dtmServer, gid).
    // The first step of the transaction is to call trans.TransSvcClient.TransOut
    // You can find the Method name for the above method in trans.pb.go as "/trans.TransSvc/TransOut"
    // dtm needs to call this method from the dtm server, so it does not take a strong type
    // Instead, it takes the dynamic url: busiServer+"/trans.TransSvc/TransOut"
		Add(busiServer+"/trans.TransSvc/TransOut", &busi.BusiReq{Amount: 30, UserId: 1}).
		Add(busiServer+"/trans.TransSvc/TransIn", &busi.BusiReq{Amount: 30, UserId: 2})
	err := msg.Submit()

The whole process is quite simple, and the previous comments are clear enough.


When looking for the path to the grpc method (/trans.TransSvc/TransOut) in the *.pb.go file, be sure to copy from Invoke call:

func (c *transSvcClient) TransOut(ctx context.Context, in *AdjustInfo, opts ...grpc.CallOption) (*Response, error) {
	out := new(Response)
	err := c.cc.Invoke(ctx, "/trans.TransSvc/TransOut", in, out, opts...)
	if err != nil {
		return nil, err
	return out, nil

Deeper Understanding Of Dynamic Calls

When using dtm's distributed transactions in go-zero, many of the calls are initiated from the dtm server, e.g. Confirm/Cancel for TCC, all calls for SAGA/MSG.

Dtm does not need to know the strong type of the relevant business api that make up the distributed transaction, it calls these api dynamically.

The call to grpc can be compared to an HTTP POST, where

  • c.BuildTarget() produces a target similar to Host in the URL
  • "/trans.TransSvc/TransOut" is equivalent to Path in the URL
  • &busi.BusiReq{Amount: 30, UserId: 1} is equivalent to Body in Post
  • pb.Response is the response to the HTTP request

With the following part of the code, dtm has the complete information and is able to launch the full call

Add(busiServer+"/trans.TransSvc/TransOut", &busi.BusiReq{Amount: 30, UserId: 1})

A More Complete Example

An enthusiastic community member, Mikael, has helped to write a more informative example that mimic a real-world application. It make a complete demonstration of a distributed transaction actually running online:

Deployment In Docker

If you are using docker for your deployment, please do not use localhost/ as host because they can not interoperating in docker.

Other ways to access

There are non-etcd alternatives to go-zero's microservices, we explain their access in order

Direct connection

For the direct connection, you can use the dtm configuration show above but just set the Target to an empty string.

In the case of a direct connection, there is no need to register the dtm to the registry


For K8S, you can use the dtm configuration show above but just set the Target to an empty string.

In K8S, the registration of services into K8S is done with deployment.yaml, and inside the application, no registration is required


Welcome to use dtm and give a star to support us.