背景
随着业务的疾速倒退、业务复杂度越来越高,微服务作为最佳解决方案之一,它解耦服务,升高复杂度,减少可维护性的同时,也带来一部分新问题。
当咱们须要跨服务保证数据一致性时,原先的数据库事务力不从心,无奈将跨库、跨服务的多个操作放在一个事务中。这样的利用场景十分多,咱们能够列举出很多:
- 跨行转账场景,数据不在一个数据库,但须要保障余额扣减和余额减少要么同时胜利,要么同时失败
- 公布文章后,更新文章总数等统计信息。其中公布文章和更新统计信息通常在不同的微服务中
- 微服务化之后的订单零碎
- 出行游览须要在第三方零碎同时定几张票
面对这些本地事务无奈解决的场景,咱们须要分布式事务的解决方案,保障跨服务、跨数据库更新数据的一致性。
go-zero与dtm强强联合,推出了在go-zero中无缝接入dtm的极简计划,让分布式事务的应用从未如此简略。
运行一个例子
咱们来看一个可运行的例子,而后再看如何本人开发实现一个残缺的分布式事务
上面以etcd作为注册服务中心,能够依照如下步骤运行一个go-zero的示例:
配置dtm
MicroService: Driver: 'dtm-driver-gozero' # 配置dtm应用go-zero的微服务协定 Target: 'etcd://localhost:2379/dtmservice' # 把dtm注册到etcd的这个地址 EndPoint: 'localhost:36790' # dtm的本地地址
启动etcd
# 前提:已装置etcdetcd
启动dtm
# 前提:已配置好dtm的数据库链接go run app/main.go dev
运行一个go-zero的服务
git clone github.com/yedf/dtmdriver-clients && cd dtmdriver-clientscd 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 12021/12/03 15:44:05 transfer in 30 cents to 22021/12/03 15:44:05 transfer out 30 cents from 12021/12/03 15:44:05 transfer out 30 cents from 1
那就是事务失常实现了
开发接入
参考yedf/dtmdriver-clients的代码
// 上面这行导入gozero的dtm驱动import _ "github.com/yedf/dtmdriver-gozero"// 应用dtm的客户端dtmgrpc之前,须要执行上面这行调用,告知dtmgrpc应用gozero的驱动来如何解决gozero的urlerr := dtmdriver.Use("dtm-driver-gozero")// check err// dtm曾经通过后面的配置,注册到上面这个地址,因而在dtmgrpc中应用该地址var dtmServer = "etcd://localhost:2379/dtmservice"// 上面从配置文件中Load配置,而后通过BuildTarget取得业务服务的地址var c zrpc.RpcClientConfconf.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帮忙写了一个内容更加丰盛的例子,结合实际利用和子事务屏障,残缺的演示了一个线上理论运行的分布式事务,有趣味的同学能够参考:
https://github.com/Mikaelemmmm/gozerodtm
其余形式接入
go-zero的微服务还有非etcd的其余形式,咱们顺次阐明他们的接入形式
直连
对于直连这种形式,您只须要在下面dtm的etcd配置根底上,将Target设置为空字符串即可。
直连的状况,不须要将dtm注册到注册核心
K8S
对于K8S这种形式,您只须要在下面dtm的etcd配置根底上,将Target设置为空字符串即可。
在K8S中,将服务注册到K8S中,是由deployment.yaml实现的,利用外部,不须要进行注册
直播分享预报
go-zero的作者和我(dtm的作者)将在12月22日晚21点,在talkgo,联结做一场《go-zero的分布式事务实际》的直播分享,将会带来更多更深刻的探讨。欢送大家届时加入。
直播地址为:https://live.bilibili.com/111...
小结
这一次go-zero与dtm的单干,在go生态中,打造了首个原生反对分布式事务的微服务解决方案,意义重大。
- go-zero我的项目地址:https://github.com/zeromicro/go-zero
- dtm我的项目地址:https://github.com/yedf/dtm
欢送大家应用咱们的go-zero
和dtm
,应用咱们原生的“分布式事务的微服务解决方案”,并star反对咱们