go-zero 实战(5)

引入Prometheus

用 Prometheus 监控应用

1. 用 docker 启动 Prometheus

编辑配置位置,我将 prometheus.yaml 和 targets.json 文件放在了 /opt/prometheus/conf目录下

prometheus.yaml

global:
  scrape_interval: 15s # 抓取间隔
  evaluation_interval: 15s # 评估间隔

scrape_configs:
  - job_name: 'file_ds'
    file_sd_configs:
    - files:
      - 'targets.json'

由于 prometheus.yaml 文件中,用到了 targets.json 文件,因此,引入 targets.json文件

targets.json

[
  {
    "targets":["192.168.10.20:9081"],
    "labels": {
      "job": "user-api",
      "app": "user-api",
      "env": "test",
      "instance": "192.168.10.20:8888"
    }    
  }
]

我的应用是启动在 宿主机的 8888 端口,因此,我这里写了宿主机的 ip 和端口。
上面的 9081 端口,可以随便写。但是要与应用中的配置一致,看后面配置。

docker run -d --name prometheus --dns=192.168.10.20 -p 9090:9090  -v /opt/prometheus/conf/prometheus.yaml:/etc/prometheus/prometheus.yml  -v /opt/prometheus/conf/targets.json:/etc/prometheus/targets.json quay.io/prometheus/prometheus

docker run -d --name prometheus --network host   -v /opt/prometheus/conf/prometheus.yaml:/etc/prometheus/prometheus.yml  -v /opt/prometheus/conf/targets.json:/etc/prometheus/targets.json quay.io/prometheus/prometheus

下面两条命令都可以启动 Prometheus。

2. 启动应用

修改应用的配置文件 userapi/etc/userapi-api.yaml 文件。

在这里插入图片描述
增加了 Prometheus 配置,端口号与 targets.json 文件中的 targets 条目标识的端口号保持一致。

3.测试

访问 http://192.168.10.20:9090/targets?search=
在这里插入图片描述
这样可以看到 Prometheus 监控了应用。

引入 jaeger

jaeger 是一个用于链路追踪的中间件。

1. docker 启动 jaeger

docker run -d -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778  -p 16686:16686 -p 14268:14268  -p 14269:14269   -p 9411:9411 jaegertracing/all-in-one:latest

这样启动的 jaeger,数据默认是放在内存中的。可以根据直接的需求,选择将数据放在 elasticsearch或其它存储中。

  • 其中 16686 是 ui 端口,直接访问 http://localhost:16686 便可以进入到 ui 界面
    在这里插入图片描述

2. 修改 userapi/etc/userapi-api.yaml 文件

在配置文件中加入如下配置:

Telemetry:
  Name: user-api
  Endpoint: http://localhost:14268/api/traces
  Sampler: 1.0
  Batcher: jaeger

3. 测试

启动 userapi 应用,用postman 访问接口。
在这里插入图片描述
这样就可以在 jaeger 的 ui 上看到访问的接口。

分布式事务

分布式事务也是微服务架构中必不可少的一部分。go-zero 使用了dtm的方案来解决分布式事务问题。

1. 引入 DTM

官网链接

1. github clone 项目

项目地址:https://github.com/dtm-labs/dtm.git

2. 进入项目

创建 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'

3. 启动dtm

从源码处启动 dtm

go run main.go -c conf.yml 

在这里插入图片描述

2. 创建表

在当前使用的微服务对应的数据中创建表。我们曾在 go-zero实战(2)中创建过zero-mall数据库。同样在该数据库创建 barrier表。

create table if not exists barrier(
	id bigint(22) primary key auto_increment,
	trans_type varchar(45),
	gid varchar(128),
	branch_id varchar(128),
	op varchar(45),
	barrier_id varchar(45),
	reason varchar(45),
	create_time datetime default now(),
	update_time datetime default now(),
	key(create_time),
	key(update_time),
	unique key(gid, branch_id, op, barrier_id)
);

3. 创建积分服务

1. 在 zero_mall 数据库中 创建 user_score 表

create table user_score(
	id bigint(0) not null auto_increment,
	user_id bigint(0) not null,
	score int(0) not null,
	primary key(id) using btree
);

2. 创建 user_score.proto 文件

syntax = "proto3";

package userscore;

option go_package = "./score";

message UserScoreRequest {
  int64 userId = 1;
  int32 score = 2;
}

message UserScoreResponse {
  int64 userId = 1;
  int32 score = 2;
}

service UserScore {
  rpc saveScore(UserScoreRequest) returns(UserScoreResponse);
  rpc saveScoreCallback(UserScoreRequest) returns(UserScoreResponse);
}

为了使用 dmt 实现的分布式事务,saveScore 方法,需要有一个相应的 Callback 方法。为了在发生异常回滚时,执行该方法。

3. 生成代码

goctl rpc protoc user_score.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.

4. 整理代码

  1. 将 生成的 user_score.pb.go 文件和 user_score_grpc.pb.go 文件放入 rpc-common 工程的score目录下。
  2. 将 userscore.go 文件放入 rpc-common 工程的 userscore 目录下。
  3. 在user-score 创建 go.mod 文件,如下:
    module user-score
    
    go 1.22.2
    
  4. 在 mall 工程下,执行如下命令:
    go work use user-score  # 加入 workspace
    go mod tidy             # 下载依赖
    
  5. 在 user-score 创建 database 目录,并增加 sqlx.go 文件,参考 go-zero 实战(3)
  6. 将user 微服务 user/internal 目录下的 dao、repo、model三个目录复制一份到 user-score 微服务的 user-score/internal 目录下并做相应的命名修改。
  7. 修改 user-score/etc/userscore.yaml 文件
    Name: score.rpc
    ListenOn: 127.0.0.1:8081
    Etcd:
      Hosts:
      - 127.0.0.1:2379
      Key: score.rpc
    Mysql:
      Datasource: root:thinker@tcp(127.0.0.1:3306)/zero_mall?charset=utf8mb4&parseTime=True&loc=Asia%2FShanghai
    
    CacheRedis:
      - Host: 127.0.0.1:6379
        Pass: thinker
        Type: node
    
  8. 修改 user-score/internal/svc/servicecontext.go 文件,加入 UserScoreRepo
  9. 修改生成的 savescorelogic.go 和 savescorecallbacklogic.go 文件

到此,积分服务创建完成。

4. 在 userapi 中调用积分服务

1. 修改 userapi/etc/userapi-api.yaml 文件

加入 user-score 微服务的 rpc 配置

UserScoreRpc:
  Etcd:
    Hosts:
      - 127.0.0.1:2379
    Key: score.rpc

2. 修改 userapi/intrenal/config/config.go 文件

在这里加入 user-score 微服务的 rpc。
在这里插入图片描述

3. 在 userapi/internal/svc/servicecontext.go 文件为上一步增加的变量赋值

在这里插入图片描述

因为userapi 是作为 rpc 客户端,而 user-score 微服务是 rpc 服务端。并且这两个服务都会用到公共的部分,于是,将公共部分抽取到 rpc-common 下。这样,userapi 微服务不会用到 user-score 微服务下的代码。

4. 修改 userapi/internal/logic/userapilogic.go 文件

我们修改了 Register 接口,增加调用 user-score 微服务的代码。

到此,算是正常走通了。在 userapi 微服务下,注册功能实现时,同时调用了 user服务和 user-score 服务。

5. 测试

在这里插入图片描述

代码,这部分代码提交到了 score 分支。

6. 使用 DTM

在上面的注册功能里,从userapi 远程调用了 user 和 user-score 两个服务。试想,如果有一个微服务调用错误,显然不会影响到另一个。我们引入分布式事务,就为了解决在注册成功后,用户能够增加积分。如果积分增加失败的情况下,也要保证注册不成功。

1. 在项目中导入 dtm

分别在 /mall/userapi、/mall/user、/mall/user-score 下执行命令:

go get github.com/dtm-labs/dtm

2. 项目中加入dtm 驱动

  1. 修改 userapi/internal/logic/userapilogic.go 文件
    加入驱动

    	_ "github.com/dtm-labs/dtmdriver-gozero"
    	// 这里的地址在文章 分布式事务 1.2 这个步骤,修改配置文件时候,指定的地址
    	// 先上看 1.2 步骤可以找到
    	var dtmServer = "etcd://localhost:2379/dtmservice" 
    

3. 修改 userapi/internal/userapilogic.go 文件

修改 Register 方法的逻辑,引入 dtm

func (l *UserLogic) Register(req *types.Request) (resp *types.Response, err error) {
	gid := dtmgrpc.MustGenGid(dtmServer)
	sagaGrpc := dtmgrpc.NewSagaGrpc(dtmServer, gid)
	userServer, err := l.svcCtx.Config.UserRpc.BuildTarget()
	if err != nil {
		return nil, err
	}

	userScoreServer, err := l.svcCtx.Config.UserScoreRpc.BuildTarget()
	if err != nil {
		return nil, err
	}

	userReq := &user.UserRequest{
		Id:     req.Id,
		Name:   req.Name,
		Gender: req.Gender,
	}
	// call save method
	sagaGrpc.Add(userServer+"/user.User/save", userServer+"/user.User/saveCallback", userReq)
	// 这个地方,应该是传入一个User,因为远程调用拿不到返回值。暂且先写死,为了测试效果。
	userScoreReq := &score.UserScoreRequest{
		UserId: req.Id,
		Score:  10,
	}

	sagaGrpc.Add(userScoreServer+"/userscore.UserScore/saveScore", userScoreServer+"/userscore.UserScore/saveScoreCallback", userScoreReq)

	sagaGrpc.WaitResult = true
	err = sagaGrpc.Submit()
	if err != nil {
		fmt.Println("---------------------------")
		fmt.Println(err)
		return nil, err
	}
	//fmt.Sprintf("register add score %d \n", userScore.Score)
	return &types.Response{
		Message: "success",
		Data:    "",
	}, nil
}

核心代码,就是将原来直接的rpc 调用,委托给 dtm 调用。

4. 修改服务端

  1. 修改 user-score/internal/logic/savescorelogic.go 文件
    引入 dtm
  2. 修改 user/internal/logic/userlogic.go 文件

5. 测试

在这里插入图片描述

指定id,插入用于,测试成功。

6. 测试事务

现在模拟 user-score 服务的逻辑出现了问题。检查事务是否生效。

在这里插入图片描述
我们用 postman测试后,发现, user 表中插入了新的数据,但是积分表中是没有新数据的。那是否事务没有生效呢?
在这里插入图片描述
当从后台打印的日志可以看出,saveCallback 方法被调用。

这里需要明白一点。

userapi/internal/logic/userapilogic.go 代码逻辑如下:

在这里插入图片描述
代码提交到了 dtm 分支。代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/638417.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS interface router scale pageTransition SlideEffect.Left ArkTS ArkUI

🎬️create Component export default struct TitleBar {build(){Row(){Text(transition).fontSize(30fp).fontColor(Color.White)}.width(100%).height(8%).backgroundColor(#4169E1).padding({left:10})}}🎞️interface export interface IList{ti…

大数据学习之安装并配置maven环境

什么是Maven Maven字面意:专家、内行Maven是一款自动化构建工具,专注服务于Java平台的项目构建和依赖管理。依赖管理:jar之间的依赖关系,jar包管理问题统称为依赖管理项目构建:项目构建不等同于项目创建 项目构建是一…

本地idea连接虚拟机linux中的docker进行打包镜像上传--maven的dockerfile-maven-plugin插件

项目名必须是英文,-,.,_,这些数字,idea需要管理员运行,因为idea控制台mvn命令需要管理员权限才能运行(maven需配置环境变量)改linux中的Docker服务文件,使用2375 进行非加密通信,然后加载重启 2.1 #修改Docker服务文件 vi /lib/systemd/system/docker.service ​ # 通常使…

TI C2000 FLASH 模拟 EEPROM

简述 FLASH和EEPROM同为非易失存储器,互有优势。 FLASH Flash是非易失性存储器(NVM)的一种形式。相对于EEPROM,Flash具有更高的存储密度和更快的写入速度。Flash内部被分为多个扇区,每个扇区都可以单独擦除和写入。但是寿命相比EEPROM较短,以TI芯片为例,flash擦写次数在…

go 微服务框架 kratos 日志库使用方法及原理探究

一、Kratos 日志设计理念 kratos 日志库相关的官方文档:日志 | Kratos Kratos的日志库主要有如下特性: Logger用于对接各种日志库或日志平台,可以用现成的或者自己实现Helper是在您的项目代码中实际需要调用的,用于在业务代码里…

正点原子LWIP学习笔记(三)PHY芯片简介

PHY芯片简介 一、PHY芯片简介(了解)二、LAN8720A与YT8512C简介(熟悉)三、PHY地址的设置(掌握)四、RMII模式选择(熟悉)五、PHY寄存器简介(熟悉) 一、PHY芯片简…

AIGC绘画设计基础-建筑设计应用

一、AI及AIGC 对于AI大家都不陌生,但是AIGC这个概念好多人其实不大清楚。“AI”是指人工智能技术本身,而“AIGC”是指基于人工智能技术而生成的内容。 生成式人工智能——AIGC(Artificial Intelligence Generated Content)&…

Java类和对象(五)—— 抽象类、接口、Object类和内部类

抽象类 在继承体系下,父类有些方法可能是要被重写的,如果我们事先就知道某些方法需要重写的话,我们可以不用在父类里面具体实现这个方法,这时候我们会用到抽象方法,这时候我们会用到关键字abstract关键字来修饰 publ…

Thinkphp内核开发盲盒商城源码v2.0 对接易支付/阿里云短信/七牛云存储

源码简介 这套系统是我从以前客户手里拿到的,100完整可用,今天测试防红链接失效了,需要修改防红API即可!前端页面展示我就不放了,懂的都懂 优点是Thinkphp开发的,二开容易。 源码图片 资源获取:Thinkphp内核开发盲盒商城源码v2.0 对接易支付/阿里云短…

有些错误,常犯常新、常新常犯:记录一个使用element-plus的tooltip组件的错误

使用element-plus的tooltip组件&#xff0c;最开始的写法是这样的&#xff1a; <el-tooltipclass"box-item"effect"dark"content"tooltip content" ><el-button v-if"isDisabled" :underline"false" type"pr…

【实战】SpringBoot整合Websocket、Redis实现Websocket集群负载均衡

文章目录 前言技术积累什么是Websocket什么是Redis发布订阅Redis发布订阅与消息队列的区别 实战演示SpringBoot整合WebsoketWebsoket集群负载均衡 实战测试IDEA启动两台服务端配置nginx负载均衡浏览器访问模拟对话 前言 相信很多同学都用过websocket来实现服务端主动向客户端推…

Web前端一套全部清晰 ⑨ day5 CSS.4 标准流、浮动、Flex布局

我走我的路&#xff0c;有人拦也走&#xff0c;没人陪也走 —— 24.5.24 一、标准流 标准流也叫文档流&#xff0c;指的是标签在页面中默认的排布规则&#xff0c;例如:块元素独占一行&#xff0c;行内元素可以一行显示多个。 二、浮动 作用: 让块级元素水平排列。 属性名:floa…

瑞米派Ubuntu系统移植指南-米尔RemiPi

1.概述 Linux系统平台上有许多开源的系统构建框架&#xff0c;这些框架方便了开发者进行嵌入式系统的构建和定制化开发&#xff0c;目前比较常见的有Buildroot, Yocto, OpenEmbedded等等。 同时更多的传统的桌面系统也加入到嵌入式环境体系中&#xff0c;如Ubuntu&#xff0c…

启动docker报错:Failed to listen on Docker Socket for the API.

说明&#xff1a; 1、安装部署docker完成后&#xff0c;启动docker报错&#xff1a;Failed to listen on Docker Socket for the API&#xff0c;如下图所示&#xff1a; 2、将SocketGroupdocker更改成&#xff1a;SocketGrouproot即可 一、解决方法&#xff1a; 1、执行命令…

用智能插件(Fitten Code: Faster and Better AI Assistant)修改好了可以持久保存的vue3留言板

天际 第一修改是选项式&#xff1a; <!-- 模板结构 --> <template><div><textarea placeholder"请输入备注内容" v-model"newItem"></textarea><button click"addItem">添加</button><hr><…

Redis 主从复制、哨兵与集群

一、Redis 主从复制 1. 主从复制的介绍 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(Master)&#xff0c;后者称为从节点(Slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。 默认情况下&a…

【MySQL精通之路】InnoDB(6)-磁盘结构(2)-索引

主博客&#xff1a; 【MySQL精通之路】InnoDB(6)-磁盘上的InnoDB结构-CSDN博客 上一篇&#xff1a; 下一篇&#xff1a; 【MySQL精通之路】磁盘上的InnoDB结构-表空间-CSDN博客 目录 1.聚集索引和二级索引 1.1 Innodb 如何建立聚集索引 1.2 聚集索引如何加快查询速度 1…

大语言模型的工程技巧(一)——GPU计算

相关说明 这篇文章的大部分内容参考自我的新书《解构大语言模型&#xff1a;从线性回归到通用人工智能》&#xff0c;欢迎有兴趣的读者多多支持。 本文涉及到的代码链接如下&#xff1a;regression2chatgpt/ch07_autograd/gpu.ipynb 本文将讨论如何利用PyTorch实现GPU计算。本…

第十一节 SpringBoot Starter 面试题

一、面试题 很多同学的简历都写着熟悉 SpringBoot&#xff0c; 而 Starter 的实现原理被当作的考题的的情况越来越多。 来源牛客网关于 starter 的一些面试题 情景一、路虎一面 情景二、蔚来 情景三、同花顺 Starter 频频出现&#xff0c;因此在面试准备时&#xff0c;这道题…

Qt_电脑wifi相关操作

项目描述: 在做项目时用到了获取wifi的操作。在网上查找了好久资料,这里做一些总结。 这里有显示当前电脑wifi连接状态,列出wifi列表,连接断开wifi等函数。欢迎大家留言添加文章内容。 使用范围: windows电脑(中文的环境) 使用技术:windows的cmd命令。和对字符串的解析…