dotnet core 也能協調分散式事務啦!

Scott Lewis 發表於 2022-06-09

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
@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 請求會被編碼成

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 請求:

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,才會以文字協議傳送。例如:

dksl:[email protected](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 的執行狀態:

$ 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