go-zero支持
dtm与go-zero进行了深度合作,打造了go-zero原生支持分布式事务的解决方案,提供了极简的用户体验。感谢go-zero作者kevwan的大力支持
dtm从v1.6.0开始原生支持go-zero微服务框架,go-zero的版本需要v1.2.4以上
运行一个已有的示例
我们以etcd作为注册服务中心为例,按照如下步骤运行一个go-zero的示例:
- 启动etcd
# 前提:已安装etcd
etcd
- 配置dtm
MicroService:
Driver: 'dtm-driver-gozero' # 配置dtm使用go-zero的微服务协议
Target: 'etcd://localhost:2379/dtmservice' # 把dtm注册到etcd的这个地址
EndPoint: 'localhost:36790' # dtm的本地地址
- 启动dtm
# 前提:配置好conf.yml
go run app/main.go -c conf.yml
- 运行一个go-zero的服务
git clone https://github.com/dtm-labs/dtmdriver-clients && cd dtmdriver-clients
cd gozero/trans && go run trans.go
- 发起一个go-zero使用dtm的事务
# 在dtmdriver-clients的目录下
cd gozero/app && go run main.go
当您在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
2021/12/03 15:44:05 transfer out 30 cents from 1
2021/12/03 15:44:05 transfer out 30 cents from 1
那就是事务正常完成了
开发接入
参考dtm-labs/dtmdriver-clients的代码
// 下面这行导入gozero的dtm驱动
import _ "github.com/dtm-labs/driver-gozero"
// dtm已经通过前面的配置,注册到下面这个地址,因此在dtmgrpc中使用该地址
var dtmServer = "etcd://localhost:2379/dtmservice"
// 下面从配置文件中Load配置,然后通过BuildTarget获得业务服务的地址
var c zrpc.RpcClientConf
conf.MustLoad(*configFile, &c)
busiServer, err := c.BuildTarget()
// 使用dtmgrpc生成一个消息型分布式事务并提交
gid := dtmgrpc.MustGenGid(dtmServer)
msg := dtmgrpc.NewMsgGrpc(dtmServer, gid).
// 事务的第一步为调用trans.TransSvcClient.TransOut
// 可以从trans.pb.go中找到上述方法对应的Method名称为"/trans.TransSvc/TransOut"
// dtm需要从dtm服务器调用该方法,所以不走强类型
// 而是走动态的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()
整个开发接入的过程很少,前面的注释已经很清晰,就不再赘述了
注意事项
在去找*.pb.go的文件中的grpc访问的方法路径时候,一定要找invoke的路径
深入理解动态调用
在go-zero使用dtm的分布式事务时,许多的调用是从dtm服务器发起的,例如TCC的Confirm/Cancel,SAGA/MSG的所有调用。
dtm无需知道组成分布式事务的相关业务api的强类型,它是动态的调用这些api。
grpc的调用,可以类比于HTTP的POST,其中:
- c.BuildTarget() 产生的target类似于URL中的Host
- “/trans.TransSvc/TransOut” 相当于URL中的Path
- &busi.BusiReq{Amount: 30, UserId: 1} 相当于Post中Body
- pb.Response 相当于HTTP请求的响应
通过下面这部分代码,dtm就拿到了完整信息,就能够发起完整的调用了
Add(busiServer+"/trans.TransSvc/TransOut", &busi.BusiReq{Amount: 30, UserId: 1})
更加完整的例子
热心的社区同学Mikael帮忙写了一个内容更加丰富的例子,结合实际应用和子事务屏障,完整的演示了一个线上实际运行的分布式事务,有兴趣的同学可以参考:
docker 中部署
接入过程中,如果你使用了docker部署,那么请参照上述两个完整例子中,关于docker的地址配置,避免因为localhost/127.0.0.1在docker中无法互通导致问题
其他方式接入
go-zero的微服务还有非etcd的其他方式,我们依次说明他们的接入方式
consul接入
dtm也支持go-zero的consul接入,需要版本1.13.2+,配置示例如下:
MicroService:
Driver: 'dtm-driver-gozero' # 配置dtm使用go-zero的微服务协议
Target: 'consul://localhost:2379/dtmservice' # 把dtm注册到consul的这个地址
EndPoint: 'localhost:36790' # dtm的本地地址
完整的示例,可以从https://github.com/Mikaelemmmm/gozerodtm找到
直连
对于直连这种方式,您只需要在上面dtm的etcd配置基础上,将Target设置为空字符串即可。
直连的情况,不需要将dtm注册到注册中心
K8S
对于K8S这种方式,您只需要在上面dtm的etcd配置基础上,将Target设置为空字符串即可。
在K8S中,将服务注册到K8S中,是有deployment.yaml完成的,应用内部,不需要进行注册
小结
欢迎使用dtm,并star支持我们,一起共建golang的微服务生态