乐趣区

关于seata:Go-Mysql-Driver-集成-SeataGolang-解决分布式事务问题

简介: 2020 年 4 月,咱们开始尝试实现 go 语言的分布式事务框架 Seata-Golang。家喻户晓,Seata AT 模式以无业务代码侵入的特点,被宽广开发者推崇。Java 版 Seata AT 模式通过对 DataSource 数据源进行代理,在 sql 语句执行时,对 sql 拦挡解析,获取数据库对应数据在 sql 语句执行前后的正本,序列化后保存起来,在 TC 协调回滚时用来回滚对应数据。实现 go 版本 client 的 AT 模式时,怎么对业务开发者更敌对,入侵更少,成了首要思考的指标。

作者 | 刘晓敏  GitHub ID:dk-lockdown
起源 | 阿里巴巴云原生公众号

背景

2020 年 4 月,咱们开始尝试实现 go 语言的分布式事务框架 Seata-Golang。家喻户晓,Seata AT 模式以无业务代码侵入的特点,被宽广开发者推崇。Java 版 Seata AT 模式通过对 DataSource 数据源进行代理,在 sql 语句执行时,对 sql 拦挡解析,获取数据库对应数据在 sql 语句执行前后的正本,序列化后保存起来,在 TC 协调回滚时用来回滚对应数据。实现 go 版本 client 的 AT 模式时,怎么对业务开发者更敌对,入侵更少,成了首要思考的指标。

应用 go 操作数据库时,咱们会应用到 go 语言的官网库 database/sql,通过 sql.Open("mysql", ${dsn}) 获取一个数据源操作对象 db。开启事务时,应用 db.Begin()db.BeginTx(ctx, &sql.TxOptions{}) 取得事务操作对象 tx,执行 sql 查问应用 tx.Query;执行 sql 新增、批改、删除,应用 tx.Exec;最初应用 tx.Commit() 提交或应用 tx.Rollback() 回滚。

go 语言官网库 database/sql 提供了一个规范形象层,通过实现不同的 driver 一套规范的形象 API 能够操作不同的数据库。开发 Go 版本的 AT 模式,必然要兼容 database/sql。通过钻研 database/sql 的 api,创立数据源操作对象,数据库无关的配置必须通过 Data Source Name (DSN) 形象传递进去,上面是 DSN 的定义:

[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]

实现 AT 模式对数据源代理是须要和事务协调器 TC 进行交互的,如果将 AT 模式实现在 driver 层,那么和 TC 交互的一些参数必须要通过 DSN 传递到 driver,这样有些毁坏它的设计。所以,最初采取了一种折中计划,在 database/sql 层之上实现 AT 模式,代理 database/sql 创立进去的数据源操作对象。数据源代理对象实现 database/sql 库定义的 Tx 接口,另外再提供一个开启事务的办法:Begin(),尽管没有齐全兼容 database/sql 的 api,然而要害接口和它的定义成一样,勉强还能承受。到此,Seata-Golang 我的项目外围性能的开发已实现。

type Tx interface {Commit() error
    Rollback() error}

转折

Seata-Golang  开源后,逐步被一些开发者理解和接触,社区也对 Seata-Golang 收回了一些反馈的声音,不少开发者并不习惯写原生 sql,他们心愿将 Seata-Golang 集成到 ORM 框架,因为过后的设计没有齐全兼容 database/sql 导致集成上遇到一些艰难。随着社区的热切召唤,且得益于后期对 driver 的一些钻研,朝思暮想必有回响,往年 3 月忽然灵感爆发:为什么参数肯定要通过 DSN 传递?Seata-Golang Client 初始化后,在须要时通过 Client 端的 API config.GetATConfig() 间接获取应用不就能够了。

于是工作之余,历时 2 周开发,第一个集成 Seata-Golang 的齐全兼容 database/sql 的 mysql driver 被开发进去,我的项目开源在 https://github.com/opentrx/mysql,现处于 beta 状态,心愿社区开发者应用后能有一些反馈,可通过例子:https://github.com/opentrx/seata-go-samples,查看应用形式并进行测试。

driver 的一些细节

  • 应用该 driver 进行分布式事务操作时,不能在 dsn 中设置 interpolateParams 参数为 true

这波及到 mysql 的两个协定:Text 协定和 Binary 协定。无关两个协定的区别,能够在文末参考文档找到材料。实现该 driver 只对 binary 协定进行了解决,开启 interpolateParams 会应用 text 协定执行 sql。

  • 应用该 driver 在须要退出全局事务组和 tc 进行交互时,须要应用 db.BeginTx(ctx context.Context, opts driver.TxOptions) 办法,并在 ctx 中退出 XID 全局事务 id 的值
ctx := context.WithValue(context.Background(), mysql.XID, c.Request.Header.Get("XID"))
tx, err := dao.BeginTx(ctx, &sql.TxOptions{
        Isolation: sql.LevelDefault,
        ReadOnly:  false,
    })

XID 传递到 driver 层,会保留在 &mysqlConn 连贯对象中,在和 TC 交互时用到。

  • 应用该 driver 的分布式事务性能前须要先初始化 seata-golang client 和 mysql driver
 config.InitConf(configPath)
  client.NewRpcClient()
  mysql.InitDataResourceManager()
  mysql.RegisterResource(config.GetATConfig().DSN)

具体可参考 seata-go-samples。

寄语

此我的项目开源到往年 4 月即满一年,通过本文中的 mysql driver,心愿能升高应用门槛,让大家真正用起来,大家在抉择微服务开发技术栈时也不必放心 go 语言没有分布式事务处理计划。

原文链接
本文为阿里云原创内容,未经容许不得转载。

退出移动版