Go Mysql Driver 集成 Seata-Golang 解决分布式事务问题

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
函数计算FC,每月15万CU 3个月
性能测试 PTS,5000VUM额度
简介: 2020 年 4 月,我们开始尝试实现 go 语言的分布式事务框架 Seata-Golang。众所周知,Seata AT 模式以无业务代码侵入的特点,被广大开发者推崇。Java 版 Seata AT 模式通过对 DataSource 数据源进行代理,在 sql 语句执行时,对 sql 拦截解析,获取数据库对应数据在 sql 语句执行前后的副本,序列化后保存起来,在 TC 协调回滚时用来回滚对应数据。实现 go 版本 client 的 AT 模式时,怎样对业务开发者更友好,入侵更少,成了首要考虑的目标。

头图.png

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

背景

2020 年 4 月,我们开始尝试实现 go 语言的分布式事务框架 Seata-Golang。众所周知,Seata AT 模式以无业务代码侵入的特点,被广大开发者推崇。Java 版 Seata AT 模式通过对 DataSource 数据源进行代理,在 sql 语句执行时,对 sql 拦截解析,获取数据库对应数据在 sql 语句执行前后的副本,序列化后保存起来,在 TC 协调回滚时用来回滚对应数据。实现 go 版本 client 的 AT 模式时,怎样对业务开发者更友好,入侵更少,成了首要考虑的目标。

1.png

使用 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.png

于是工作之余,历时 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 语言没有分布式事务处理方案。另外,此项目还很年轻,仍有许多需要完善的地方,希望感兴趣的朋友一起参与到社区来对它进行完善!希望听到社区更多用户的反馈!
如果你有任何疑问,欢迎钉钉扫码加入交流群【钉钉群号 33069364】:

3.png

作者简介

刘晓敏 (GitHubID dk-lockdown),目前就职于 h3c 成都分公司,擅长使用 Java/Go 语言,在云原生和微服务相关技术方向均有涉猎,目前专攻分布式事务。

参考资料

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
定时任务在企业应用中至关重要,常用于异步数据处理、自动化运维等场景。在单体应用中,利用Java的`java.util.Timer`或Spring的`@Scheduled`即可轻松实现。然而,进入微服务架构后,任务可能因多节点并发执行而重复。Spring Cloud Alibaba为此发布了Scheduling模块,提供轻量级、高可用的分布式定时任务解决方案,支持防重复执行、分片运行等功能,并可通过`spring-cloud-starter-alibaba-schedulerx`快速集成。用户可选择基于阿里云SchedulerX托管服务或采用本地开源方案(如ShedLock)
126 1
|
2月前
|
SQL NoSQL 数据库
SpringCloud基础6——分布式事务,Seata
分布式事务、ACID原则、CAP定理、Seata、Seata的四种分布式方案:XA、AT、TCC、SAGA模式
SpringCloud基础6——分布式事务,Seata
|
2月前
|
监控 关系型数据库 MySQL
zabbix agent集成percona监控MySQL的插件实战案例
这篇文章是关于如何使用Percona监控插件集成Zabbix agent来监控MySQL的实战案例。
59 2
zabbix agent集成percona监控MySQL的插件实战案例
|
4月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
Spring Cloud Alibaba 发布了 Scheduling 任务调度模块 [#3732]提供了一套开源、轻量级、高可用的定时任务解决方案,帮助您快速开发微服务体系下的分布式定时任务。
14953 29
|
3月前
|
NoSQL 关系型数据库 MySQL
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
149 2
|
3月前
|
Java 关系型数据库 MySQL
SpringBoot 集成 Quartz + MySQL
SpringBoot 集成 Quartz + MySQL
116 1
|
3月前
|
缓存 NoSQL 关系型数据库
(八)漫谈分布式之缓存篇:唠唠老生常谈的MySQL与Redis数据一致性问题!
本文来聊一个跟实际工作挂钩的老生常谈的问题:分布式系统中的缓存一致性。
154 11
|
3月前
|
关系型数据库 MySQL 数据库
SpringCloud2023中使用Seata解决分布式事务
对于分布式系统而言,需要保证分布式系统中的数据一致性,保证数据在子系统中始终保持一致,避免业务出现问题。分布式系统中对数据的操作要么一起成功,要么一起失败,必须是一个整体性的事务。Seata简化了这个使用过程。
89 2
|
3月前
|
Java 关系型数据库 MySQL
(二十七)舞动手指速写一个Seata-XA框架解决棘手的分布式事务问题
相信大家对于事务问题都不陌生,在之前《MySQL事务篇》中曾详解过MySQL的事务机制,在传统的单库环境下开发,咱们可依赖于MySQL所提供的事务机制,来确保单个事务内的一组操作,要么全部执行成功,要么全部执行失败。
|
4月前
|
Java 关系型数据库 MySQL
如何实现Springboot+camunda+mysql的集成
【7月更文挑战第2天】集成Spring Boot、Camunda和MySQL的简要步骤: 1. 初始化Spring Boot项目,添加Camunda和MySQL驱动依赖。 2. 配置`application.properties`,包括数据库URL、用户名和密码。 3. 设置Camunda引擎属性,指定数据源。 4. 引入流程定义文件(如`.bpmn`)。 5. 创建服务处理流程操作,创建控制器接收请求。 6. Camunda自动在数据库创建表结构。 7. 启动应用,测试流程启动,如通过服务和控制器开始流程实例。 示例代码包括服务类启动流程实例及控制器接口。实际集成需按业务需求调整。
374 4
下一篇
无影云桌面