关于golang:kratos分布式事务实践

64次阅读

共计 2277 个字符,预计需要花费 6 分钟才能阅读完成。

背景

随着业务的疾速倒退、业务复杂度越来越高,微服务作为最佳解决方案之一,它解耦服务,升高复杂度,减少可维护性的同时,也带来一部分新问题。

当咱们须要跨服务保证数据一致性时,原先的数据库事务力不从心,无奈将跨库、跨服务的多个操作放在一个事务中。这样的利用场景十分多,咱们能够列举出很多:

  • 跨行转账场景,数据不在一个数据库,但须要保障余额扣减和余额减少要么同时胜利,要么同时失败
  • 公布文章后,更新文章总数等统计信息。其中公布文章和更新统计信息通常在不同的微服务中
  • 微服务化之后的订单零碎
  • 出行游览须要在第三方零碎同时定几张票

面对这些本地事务无奈解决的场景,咱们须要分布式事务的解决方案,保障跨服务、跨数据库更新数据的一致性。

dtm 作为一款十分风行的分布式事务框架,曾经反对了接入多种微服务框架,上面咱们就来着重介绍一下 go-kratos 如何接入 dtm,解决分布式事务的问题

运行一个例子

咱们来看一个可运行的例子,而后再看如何本人开发实现一个残缺的分布式事务

上面以 etcd 作为注册服务中心,能够依照如下步骤运行一个 kratos 的示例:

  • 配置 dtm

    MicroService:
     Driver: 'dtm-driver-kratos' # name of the driver to handle register/discover
     Target: 'discovery://127.0.0.1:2379/dtmservice' # register dtm server to this url
     EndPoint: 'grpc://localhost:36790'
  • 启动 etcd

    # 前提:已装置 etcd
    etcd
  • 启动 dtm

    # 请先配置好 dtm 的数据库
    go run app/main.go -c conf.yml # conf.yml 为你对应的 dtm 配置文件 
  • 运行一个 kratos 的服务

    git clone https://github.com/dtm-labs/dtmdriver-clients && cd dtmdriver-clients
    cd kratos/trans
    make build && ./bin/trans -conf configs/config.yaml
  • 发动一个 kratos 应用 dtm 的事务

    # 在 dtmdriver-clients 的目录下
    cd kratos/app && go run main.go

当您在 trans 的日志中看到

INFO msg=config loaded: config.yaml format: yaml
INFO msg=[gRPC] server listening on: [::]:9000
2022/03/30 09:35:36 transfer out 30 cents from 1
2022/03/30 09:35:36 transfer in 30 cents to 2

那就是事务失常实现了

开发接入

参考 dtm-labs/dtmdriver-clients 的代码

// 上面这些导入 kratos 的 dtm 驱动
import (_ "github.com/dtm-labs/driver-kratos")

// dtm 曾经通过后面的配置,注册到上面这个地址,因而在 dtmgrpc 中应用该地址
var dtmServer = "discovery://localhost:2379/dtmservice"

// 业务地址,上面的 busi 换成理论在 server 初始化设置的名字
var busiServer = "discovery://localhost:2379/busi"

// 发动一个 msg 事务,保障 TransOut 和 TransIn 都会实现
gid := dtmgrpc.MustGenGid(dtmServer)
m := dtmgrpc.NewMsgGrpc(dtmServer, gid).
  Add(busiServer+"/api.trans.v1.Trans/TransOut", &busi.BusiReq{Amount: 30, UserId: 1}).
  Add(busiServer+"/api.trans.v1.Trans/TransIn", &busi.BusiReq{Amount: 30, UserId: 2})
m.WaitResult = true
err := m.Submit()
logger.FatalIfError(err)

深刻了解动静调用

在 kratos 应用 dtm 的分布式事务时,许多的调用是从 dtm 服务器发动的,例如 TCC 的 Confirm/Cancel,SAGA/MSG 的所有调用。

dtm 无需晓得组成分布式事务的相干业务 api 的强类型,它是动静的调用这些 api。

grpc 的调用,能够类比于 HTTP 的 POST,其中:

  • “/api.trans.v1.Trans/TransIn” 相当于 URL 中的 Path。请留神这个 Path 肯定是要从 TransIn 的 Invoke 函数实现外面找
  • &busi.BusiReq{Amount: 30, UserId: 1} 相当于 Post 中 Body
  • v1.Response 相当于 HTTP 申请的响应

通过上面这部分代码,dtm 就拿到了残缺信息,就可能发动残缺的调用了

Add(busiServer+"/api.trans.v1.Trans/TransIn", &busi.BusiReq{Amount: 30, UserId: 1})

其余形式接入

kratos 的微服务还有非 etcd 的其余形式,上面列出它们的接入形式

直连

对于直连这种形式,您只须要在下面 dtm 的 etcd 配置根底上,将 Target 设置为空字符串即可。

直连的状况,不须要将 dtm 注册到注册核心

小结

欢送应用 dtm,并 star 反对咱们,一起共建 golang 的微服务生态

正文完
 0