dotnet core 也能协调分布式事务啦!

2022-07-02 13:38:09 浏览数 (2)

2022 年 5 月 24 日,我们发布了 DBPack v0.1.0 版本,该版本主要 release 了分布式事务功能。在我们的规划里,DBPack 是要支持所有微服务开发语言协调分布式事务的,但经过社区反馈,dotnet core 并不支持。于是,我们在 v0.1.1 对 dotnet core 进行了支持。下面就如何支持 dotnet core 做一个说明。

MySql 协议

先请允许我对 MySql 的通信协议做一个简单的介绍。MySql 支持两种协议,一种是文本(Text)协议,一种是二进制(Binary)协议。MySql 客户端使用 COM_QUERY 发出的请求,MySql 服务端会以文本协议响应结果;使用 COM_STMT_EXECUTE 命令发出的请求,会以二进制协议响应结果。

在我们用程序调用 MySql Client SDK 发起请求的时候,不同的 MySql Client SDK 会默认使用不同的协议发送请求,但大部分 MySql Client SDK 都支持文本协议和二进制协议,我们可以通过修改属性配置改变 MySql Client SDK 的默认行为。比如:

  • JAVA
代码语言:javascript复制
@Mapper
public interface ProductMapper {
    @Update("UPDATE /*  XID('${xid}') */ `product`.`inventory` SET `available_qty` = `available_qty` - #{qty}, allocated_qty = allocated_qty   #{qty} WHERE product_sysno = #{productSysNo} AND available_qty >= #{qty}")
    boolean allocateInventory(@Param("xid") String xid, @Param("productSysNo") long productSysNo, @Param("qty") int qty);
}

在 java 语言编写的微服务中,我们写了一个方法去修改商品的库存,当我们传入参数提交执行的时候,默认该 SQL 请求会被编码成

代码语言:javascript复制
update /*  XID('gs/aggregationSvc/81336085455405058') */ product.inventory set available_qty = available_qty - 2, allocated_qty = allocated_qty   2 where product_sysno = 1 and available_qty >= 2;

通过 COM_QUERY 命令发出。

我们可以通过修改连接字符串,在原来的 jdbc:mysql://dbpack2:13307/product 上加上 useServerPrepStmts=true,改为 jdbc:mysql://dbpack2:13307/product?useServerPrepStmts=true,再次执行时,会首先发出 COM_STMT_PREPARE 请求:

代码语言:javascript复制
UPDATE /*  XID('gs/aggregationSvc/2612341069705662465') */ product.inventory set available_qty = available_qty - ?, allocated_qty = allocated_qty   ? WHERE product_sysno = ? and available_qty >= ?

获取到 statement id 后,再将 statement id 和请求参数编码后通过 COM_STMT_EXECUTE 命令发出。

  • Golang

Golang MySql driver 默认是以二进制协议发送带参数的 DML 请求的,通过在 dsn 上加上参数 interpolateParams=true,才会以文本协议发送。例如:

代码语言:javascript复制
dksl:123456@tcp(127.0.0.1:13306)/employees?interpolateParams=true&timeout=10s&readTimeout=10s&writeTimeout=10s&parseTime=true&loc=Local&charset=utf8mb4,utf8

Dotnet Core

Dotnet core 如果使用 EntityFrameworkCore 或者 Dapper 来访问数据库,目前还不支持使用 Prepared Statement,下面这两个 issue 有相关说明:

https://github.com/dotnet/efcore/issues/5459

https://github.com/DapperLib/Dapper/issues/474

在 v0.1.0 版本,我们只对 COM_STMT_EXECUTE 请求做了拦截处理,来协调分布式事务问题。dotnet core 使用 COM_QUERY 提交请求自然无法协调分布式事务,在 v0.1.1 我们增加了 COM_QUERY 请求协调分布式事务的支持,这样真正做到了支持所有微服务语言协调分布式事务。

dotnet core sample 见:https://github.com/CECTC/dbpack-samples/tree/main/dotnet。

其他特性

本次发版,还修复了一些 bug,增加了 status api 用于查询 dbpack 的运行状态:

代码语言:javascript复制
$ curl http://localhost:9999/status
$ {
	"listeners": [{
		"protocol_type": "mysql",
		"socket_address": {
			"address": "0.0.0.0",
			"port": 13306
		},
		"active": true
	}],
	"distributed_transaction_enabled": true,
	"is_master": true
}

至此,我们有了

  • /live
  • /ready
  • /status
  • /metrics

这些 api 辅助我们查看 dbpack 的运行状态。

完整的版本变更日志请看 https://github.com/CECTC/dbpack/releases。

在下一个版本,我们会增加 tracing 和审计日志的功能。

一些链接

DBPack 项目地址:https://github.com/cectc/dbpack

DBPack 文档:https://cectc.github.io/dbpack-doc/#/

DBPack-samples:https://github.com/cectc/dbpack-samples

DBPack 介绍:https://mp.weixin.qq.com/s/DmXfk5bAcVYdnOwvp8ocHA

事件驱动的分布式事务架构设计:https://mp.weixin.qq.com/s/r43JvRY3LCETMoZjrdNxXA

0 人点赞