当前位置: 首页 > news >正文

Golang基于DTM的分布式事务TCC实战

Golang基于DTM的分布式事务SAGA实战-CSDN博客

源代码:https://github.com/Ssummer520/dtm-gin


代码在宿主机运行 docker network:bridge

docker安装,安装成功后可以访问http://localhost:36789/ 打开dtm事务web-ui


docker run -itd  --name dtm -p 36789:36789 -p 36790:36790  yedf/dtm:latest

部署mysql

基于docker部署

  docker run -d \--name mysql-latest \-e MYSQL_ROOT_PASSWORD=sa123456 \-e MYSQL_USER=sa \-e MYSQL_PASSWORD=sa123456 \-e MYSQL_DATABASE=test\-p 3306:3306 \-v db_data:/var/lib/mysql \mysql:latest

dtm子事务屏障

异常与子事务屏障 | DTM开源项目文档

准备 RM 数据表

子事务依赖屏障表

子事务屏障技术依赖本地数据库中创建子事务屏障相关的表(barrier),在源代码的示例中默认的数据库和表分别为(部署依赖的数据库)

库:dtm_barrier

表:barrier(子事务屏障依赖表)

我们创建上面的库表,如果需要自定义库表名称

create database if not exists dtm_barrier
/*!40100 DEFAULT CHARACTER SET utf8mb4 */
;
drop table if exists dtm_barrier.barrier;
create table if not exists dtm_barrier.barrier(id bigint(22) PRIMARY KEY AUTO_INCREMENT,trans_type varchar(45) default '',gid varchar(128) default '',branch_id varchar(128) default '',op varchar(45) default '',barrier_id varchar(45) default '',reason varchar(45) default '' comment 'the branch type who insert this record',create_time datetime DEFAULT now(),update_time datetime DEFAULT now(),key(create_time),key(update_time),UNIQUE key(gid, branch_id, op, barrier_id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
转账微服务依赖库表

库:busi

表:user_account

CREATE DATABASE if not exists dtm_busi
/*!40100 DEFAULT CHARACTER SET utf8mb4 */
;
drop table if exists dtm_busi.user_account;
create table if not exists dtm_busi.user_account(id int(11) PRIMARY KEY AUTO_INCREMENT,user_id int(11) UNIQUE,balance DECIMAL(10, 2) not null default '0',trading_balance DECIMAL(10, 2) not null default '0',create_time datetime DEFAULT now(),update_time datetime DEFAULT now(),key(create_time),key(update_time)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
insert into dtm_busi.user_account (user_id, balance)
values (1, 10000),(2, 10000) on DUPLICATE KEY
UPDATE balance =
values (balance);

ddl和数据

/*Navicat Premium Dump SQLSource Server         : localhost_3306Source Server Type    : MySQLSource Server Version : 80039 (8.0.39)Source Host           : localhost:3306Source Schema         : testTarget Server Type    : MySQLTarget Server Version : 80039 (8.0.39)File Encoding         : 65001Date: 17/08/2024 10:44:02
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for user_account
-- ----------------------------
DROP TABLE IF EXISTS `user_account`;
CREATE TABLE `user_account` (`id` int NOT NULL AUTO_INCREMENT,`user_id` int NOT NULL,`balance` decimal(10,2) NOT NULL DEFAULT '0.00',`trading_balance` decimal(10,2) NOT NULL DEFAULT '0.00',`create_time` datetime DEFAULT CURRENT_TIMESTAMP,`update_time` datetime DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`),UNIQUE KEY `user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;-- ----------------------------
-- Records of user_account
-- ----------------------------
BEGIN;
INSERT INTO `user_account` (`id`, `user_id`, `balance`, `trading_balance`, `create_time`, `update_time`) VALUES (1, 1000, 11051.00, 0.00, '2024-08-16 09:19:44', '2024-08-16 13:52:11');
INSERT INTO `user_account` (`id`, `user_id`, `balance`, `trading_balance`, `create_time`, `update_time`) VALUES (2, 1001, 11051.00, 0.00, '2024-08-16 09:20:13', '2024-08-16 13:52:11');
COMMIT;SET FOREIGN_KEY_CHECKS = 1;
允许空回滚

如图我们模拟丢包的问题,让try阶段没有进行依赖于 gin框架引入timeout中间件进行控制

func timeoutMiddleware(duration time.Duration) gin.HandlerFunc {return func(c *gin.Context) {ctx, cancel := context.WithTimeout(c.Request.Context(), duration)defer cancel()c.Request = c.Request.WithContext(ctx)done := make(chan struct{})go func() {c.Next()close(done)}()select {case <-ctx.Done():c.JSON(http.StatusGatewayTimeout, gin.H{"error": "request timed out"})c.Abort()case <-done:}}
}

我们在代码里面sleep3秒中http自定义配置会引起超时timeout

结果:

dtm一阶段timeout

rm1 因我们sleep之后直接进行了return

rm2 try之后触发cancel

数据库金额未发生变化 只看到第二条数据update_time发生的变更

防悬挂控制

我们在上面基础上取掉return 通过timeout中间件触发timeout

dtm触发timeout

rm1触发timeout之后紧接着触发cancel

rm2正常进行tcc流程rm1失败立即回滚

结果

幂等 

幂等我们在dtm多次传入相同的全局事务id 操作只有一次会成功

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Golang | Leetcode Golang题解之第343题整数拆分
  • 16.2 TensorFlow 与 Keras 基础
  • 图表:调用FluentUI中的折线图散点图和饼状图
  • 八股之数据库
  • 无缝融入,即刻智能[二]:Dify-LLM平台(聊天智能助手、AI工作流)快速使用指南,42K+星标见证专属智能方案
  • 第二章 pytorch回归问题
  • Java、python、php版的企业单位考勤打卡管理系统的设计与实现(源码、调试、LW、开题、PPT)
  • 深度学习·Pytorch
  • Java TCP练习1
  • 部署 K8s 图形化管理工具 Dashboard
  • 【与C++的邂逅】--- 类和对象(上)
  • 【数据结构-1】二叉树
  • haproxy负载均衡(twenty-eight day)
  • C# 重载运算符
  • web自动化测试Day5
  • [笔记] php常见简单功能及函数
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 2017-08-04 前端日报
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • git 常用命令
  • mysql 数据库四种事务隔离级别
  • redis学习笔记(三):列表、集合、有序集合
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 大数据与云计算学习:数据分析(二)
  • 服务器之间,相同帐号,实现免密钥登录
  • 讲清楚之javascript作用域
  • 京东美团研发面经
  • 强力优化Rancher k8s中国区的使用体验
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 【干货分享】dos命令大全
  • PostgreSQL之连接数修改
  • ​2020 年大前端技术趋势解读
  • ​ArcGIS Pro 如何批量删除字段
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • (007)XHTML文档之标题——h1~h6
  • (1)Nginx简介和安装教程
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (2024最新)CentOS 7上在线安装MySQL 5.7|喂饭级教程
  • (二)构建dubbo分布式平台-平台功能导图
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (七)c52学习之旅-中断
  • (一) storm的集群安装与配置
  • (一)为什么要选择C++
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • (转载)从 Java 代码到 Java 堆
  • .net core Swagger 过滤部分Api
  • .NET 中的轻量级线程安全
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .Net下C#针对Excel开发控件汇总(ClosedXML,EPPlus,NPOI)
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • [ linux ] linux 命令英文全称及解释
  • [24年新算法]NRBO-XGBoost回归+交叉验证基于牛顿拉夫逊优化算法-XGBoost多变量回归预测
  • [C][数据结构][树]详细讲解