Go最全go-zero学习 第六章 分布式事务dtm_gozero分布式事务(1),2024年最新记录下我磕磕碰碰的三个月找工作经历

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!


在转入操作失败的情况下,`TransIn`和`TransOut`的补偿操作被执行,保证了最终的余额和转账前是一样的。


## 3 go-zero使用dtm参考代码


### 3.1 go-zero支持dtm 代码操作步骤


参考:[go-zero支持dtm]( ):官方讲解+代码


**注意**:这里只是从调用方角度展示了如何使用dtm的代码,而关于被调用方的代码缺失,需要结合`3.2 gozerodtm 代码操作步骤`。


1. 启动`Etcd`,查看所有`key`命令:`etcdctl.exe get --prefix ""`
2. 把[dtm]( ) `clone`下来
3. 找到`dtm`项目根文件夹下的`conf.sample.yml`,复制一份名称改为`conf.yml`
4. 把`conf.yml`中的下面这段注释放开:



MicroService: # gRPC/HTTP based microservice config
Driver: ‘dtm-driver-gozero’ # name of the driver to handle register/discover
Target: ‘etcd://localhost:2379/dtmservice’ # register dtm server to this url
EndPoint: ‘localhost:36790’


* `MicroService`:这个不要动,这个代表要对把`dtm`注册到那个微服务服务集群里面去,使微服务集群内部服务可以通过`grpc`直接跟`dtm`交互
* `Driver` :`'dtm-driver-gozero'`, 使用`go-zero`的注册服务发现驱动,支持`go-zero`。
* `Target`: `'etcd://localhost:2379/dtmservice'`将当前`dtm`的`server`直接注册到微服务所在的`etcd`集群中,如果`go-zero`作为微服务使用的话,就可以直接通过`etcd`拿到`dtm`的`server grpc`链接,直接就可以跟`dtm server`交互了。
* `EndPoint`: `'localhost:36790'` , 代表的是`dtm`的`server`的连接地址+端口 , 集群中的微服务可以直接通过`etcd`获得此地址跟`dtm`交互了,如果你自己去改了`dtm`源码`grpc`端口,记得这里要改下端口。


5. 启动`dtm`



前提:配置好conf.yml

go run main.go -c conf.yml


如果是用`Goland`启动,则需要将 `-c conf.yml`作为参数填写到`Program arguments`中。


6. 运行一个`go-zero`的服务



git clone https://github.com/dtm-labs/dtmdriver-clients && cd dtmdriver-clients
cd gozero/trans && go run trans.go


7. 发起一个`go-zero`使用`dtm`的事务



在dtmdriver-clients的目录下

cd gozero/app && go run main.go


8. 在`trans`的日志中看到记录信息,就是事务正常完成了



2023/07/24 21:45:47 transfer out 30 cents from 1
2023/07/24 21:45:47 transfer in 30 cents to 2
2023/07/24 21:45:47 transfer out 30 cents from 1
2023/07/24 21:45:47 transfer out 30 cents from 1


### ※3.2 gozerodtm 代码操作步骤


参考:[gozerodtm]( ):Mikaelemmmm代码


**项目介绍:**


* `order-api`是`http`服务入口。
* `order-srv`是订单的`rpc`服务,与`dtm-gozero-order`数据库中`order`表交互。
* `stock-srv`是库存的`rpc`服务,与`dtm-gozero-stock`数据库中`stock`表交互。


**整体流程:**  
 `http`调用`order-api`中立即下单接口,然后`order-api`立即下单接口会去调用`order-srv`创建订单并且调用`stock-srv`扣减库存,因为`order-srv`与`stock-srv`是2个独立`grpc`服务,所以使用`dtm`来做分布式事务协调。


前5步与3.1完全一致。


1. 创建数据库表  
 在项目的`datasql`目录下分别有:`order-srv`服务的`dtm-gozero-order.sql`、`stock-srv`服务的`dtm-gozero-stock.sql`,在数据库按照创建两个数据库并执行相关`sql`。
2. 修改数据库连接配置  
 分别修改 `order-srv`、`stock-srv`服务的`yaml`中的数据库连接配置。
3. 修改启动类读取配置文件的路径  
 分别修改`order-api`、`order-srv`、`stock-srv`中读取`yaml`配置的路径。
4. 启动服务  
 依次启动`order-srv`、`stock-srv`、`order-api`服务
5. 请求测试  
 使用`POSTMAN`测试:  
 请求地址:<http://localhost:8889/order/quickCreate>  
 请求方式:`POST`  
 数据格式:`JSON`  
 请求数据:`{"userId":2,"goodsId":1,"num":20}`
6. 测试结果  
 HTTP请求响应成功,状态是200,但是查看[DTM服务]( )发现,操作失败,且数据库中数据未改变。  
 原因排查:  
 依次查看`order-api`、`order-srv`、`stock-srv`服务后,发现在`order-srv`服务有报错,主要报错信息:



{“level”:“error”,“ts”:“2023-07-25T14:08:24.891+0800”,“caller”:“dtmimp/utils.go:207”,“msg”:"used: 0 ms exec error: Error 1146: Table ‘dtm_barrier.barrier’ doesn’t exist for insert i
gnore into dtm_barrier.barrier(trans_type, gid, branch_id, op, barrier_id, reason) values(?,?,?,?,?,?)


推断是缺少`dtm_barrier`数据库以及`barrier`数据表。


7. 创建`dtm_barrier`数据库以及`barrier`数据表



/*
Navicat Premium Data Transfer

Source Server : 本机
Source Server Type : MySQL
Source Server Version : 50737
Source Host : 127.0.0.1:3357
Source Schema : dtm_barrier

Target Server Type : MySQL
Target Server Version : 50737
File Encoding : 65001

Date: 25/07/2023 14:06:43
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;


– Table structure for barrier


DROP TABLE IF EXISTS barrier;
CREATE TABLE barrier (
id bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘ID’,
trans\_type varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
gid varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
branch\_id varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
op varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
barrier\_id bigint(20) NULL DEFAULT NULL,
reason varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
create\_time datetime(0) NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0),
PRIMARY KEY (id) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = ‘dtm子屏障数据表’ ROW_FORMAT = DYNAMIC;

SET FOREIGN_KEY_CHECKS = 1;


8. 重新请求测试  
 HTTP请求响应成功,状态是200,[DTM服务]( )中状态显示操作成功,且数据库中数据改变。


## 4 注意事项


在`3.1 go-zero支持dtm 代码操作步骤`和`※3.2 gozerodtm 代码操作步骤`有一些操作注意事项。


**重点是子事务如何处理 `回滚`、`补偿`等操作,这一块需要特别留意。**


### 4.1 grpc接口地址


在找grpc访问的方法路径时候,是在`***.pb.go`的文件中找该方法`invoke`的路径。  
 原因:当proto文件方法名字都是大写,这2者都一样如果proto中方法名字小写的,invoke中跟他的方法名就不一样了  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a2ee32738c7743478026f01a5bd6fa06.png)  
 仔细观察发现两个路径有大小写之分!  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/976fcaed8fe8410a88ae47f2cb340455.png)


### ※4.2 动态调用过程


在go-zero使用dtm的分布式事务时,许多的调用是从dtm服务器发起的,例如TCC的Confirm/Cancel,SAGA/MSG的所有调用。


dtm无需知道组成分布式事务的相关业务api的强类型,它是动态的调用这些api。


grpc的调用,可以类比于HTTP的POST,其中:


* c.BuildTarget() 产生的target类似于URL中的Host
* “/trans.TransSvc/TransOut” 相当于URL中的Path
* &busi.BusiReq{Amount: 30, UserId: 1} 相当于Post中Body
* pb.Response 相当于HTTP请求的响应


通过下面这部分代码,dtm就拿到了完整信息,就能够发起完整的调用了



Add(busiServer+“/trans.TransSvc/TransOut”, &busi.BusiReq{Amount: 30, UserId: 1})


### 4.3 dtm的回滚补偿


在使用dtm的grpc时候,当我们使用saga、tcc等如果第一步尝试或者执行失败了,是希望它能执行后面的rollback的,在grpc中的服务如果发生错误了,必须返回 : status.Error(codes.Aborted, dtmcli.ResultFailure) , 返回其他错误,不会执行你的rollback操作,dtm会一直重试,如下图:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/effc98c9db45461bb2f181ecb78ffc67.png)


### 4.4 `barrier`的空补偿、悬挂等


这一步需要创建`dtm_barrier`数据库以及`barrier`数据表。这个其实就是为我们的业务服务做了一个检查,防止空补偿,具体可以看barrier.Call中源码,没几行代码可以看懂的。


每个与`db`交互的服务只要用到了`barrier`,都需要这个。


### 4.5 `barrier`在`rpc`中本地事务


在rpc的业务中,如果使用了barrier的话,那么在model中与db交互时候必须要用事务,并且一定要跟barrier用同一个事务。  
 logic:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/9a53a1c862c240e1bfc90b706ec92a00.png#pic_center)  
 model:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/594b5638ef9841b1833e2016df77e93b.png#pic_center)






![img](https://img-blog.csdnimg.cn/img_convert/9e35142f76bdba9abfd7b51e8b2380f8.png)
![img](https://img-blog.csdnimg.cn/img_convert/2b7b09a5cc21f5098e2035e638cd7ed1.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

存中...(img-KXBf29Ri-1715812809611)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 11
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值