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/prometheusdocker 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-apiEndpoint: http://localhost:14268/api/tracesSampler: 1.0Batcher: 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 configDriver: 'dtm-driver-gozero' # name of the driver to handle register/discoverTarget: 'etcd://localhost:2379/dtmservice' # register dtm server to this urlEndPoint: '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. 整理代码
- 将 生成的 user_score.pb.go 文件和 user_score_grpc.pb.go 文件放入 rpc-common 工程的score目录下。
- 将 userscore.go 文件放入 rpc-common 工程的 userscore 目录下。
- 在user-score 创建 go.mod 文件,如下:
module user-scorego 1.22.2
- 在 mall 工程下,执行如下命令:
go work use user-score # 加入 workspace go mod tidy # 下载依赖
- 在 user-score 创建 database 目录,并增加 sqlx.go 文件,参考 go-zero 实战(3)
- 将user 微服务 user/internal 目录下的 dao、repo、model三个目录复制一份到 user-score 微服务的 user-score/internal 目录下并做相应的命名修改。
- 修改 user-score/etc/userscore.yaml 文件
Name: score.rpc ListenOn: 127.0.0.1:8081 Etcd:Hosts:- 127.0.0.1:2379Key: score.rpc Mysql:Datasource: root:thinker@tcp(127.0.0.1:3306)/zero_mall?charset=utf8mb4&parseTime=True&loc=Asia%2FShanghaiCacheRedis:- Host: 127.0.0.1:6379Pass: thinkerType: node
- 修改 user-score/internal/svc/servicecontext.go 文件,加入 UserScoreRepo
- 修改生成的 savescorelogic.go 和 savescorecallbacklogic.go 文件
到此,积分服务创建完成。
4. 在 userapi 中调用积分服务
1. 修改 userapi/etc/userapi-api.yaml 文件
加入 user-score 微服务的 rpc 配置
UserScoreRpc:Etcd:Hosts:- 127.0.0.1:2379Key: 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 驱动
-
修改 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 methodsagaGrpc.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 = trueerr = 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. 修改服务端
- 修改 user-score/internal/logic/savescorelogic.go 文件
引入 dtm - 修改 user/internal/logic/userlogic.go 文件
5. 测试
指定id,插入用于,测试成功。
6. 测试事务
现在模拟 user-score 服务的逻辑出现了问题。检查事务是否生效。
我们用 postman测试后,发现, user 表中插入了新的数据,但是积分表中是没有新数据的。那是否事务没有生效呢?
当从后台打印的日志可以看出,saveCallback 方法被调用。
这里需要明白一点。
userapi/internal/logic/userapilogic.go 代码逻辑如下:
代码提交到了 dtm 分支。代码
相关文章:

go-zero 实战(5)
引入Prometheus 用 Prometheus 监控应用 1. 用 docker 启动 Prometheus 编辑配置位置,我将 prometheus.yaml 和 targets.json 文件放在了 /opt/prometheus/conf目录下 prometheus.yaml global:scrape_interval: 15s # 抓取间隔evaluation_interval: 15s # 评估…...

Python异常处理:打造你的代码防弹衣!
Hi,我是阿佑,上文咱们讲到——揭秘Python的魔法:装饰器的超能力大揭秘 ♂️✨,阿佑将带领大家通过精准捕获异常、使用with语句和上下文管理器、以及异常链等高级技巧来增强代码的健壮性。就像为代码穿上防弹衣,保护它…...

Linux——进程与线程
进程与线程 前言一、Linux线程概念线程的优点线程的缺点线程异常线程用途 二、Linux进程VS线程进程和线程 三、Linux线程控制创建线程线程ID及进程地址空间布局线程终止线程等待分离线程 四、习题巩固请简述什么是LWP请简述LWP与pthread_create创建的线程之间的关系简述轻量级进…...

ping 探测网段哪些地址被用
#!/bin/bash# 遍历192.168.3.1到192.168.3.254 for i in {1..254} doip"192.168.3.$i"# 对每个IP地址进行三次ping操作if ping -c 3 -W 1 $ip > /dev/null 2>&1thenecho "$ip: yes"fi done$ sh test.sh 192.168.3.1: yes 192.168.3.95: yes 192.…...

OSPF问题
.ospf 选路 域内 --- 1类,2类LSA 域间 --- 3类LSA 域外 --- 5类,7类LSA --- 根据开销值的计算规则不同,还分为类型1和类型2 ospf 防环机制 区域内防环:在同一OSPF区域内,所有路由器通过交换链路状态通告ÿ…...
asgasgas
asdgasdgsa...

Go语言实现人脸检测(Go的OpenCV绑定库)
文章目录 OpenCVGithub官网安装环境变量 Go的OpenCV绑定库Github文档安装搜索视频设备ID显示视频检测人脸 OpenCV Github https://github.com/opencv/opencv/ 官网 https://opencv.org/ 安装 brew install opencv brew upgrade opencv安装目录 cd /usr/local/opt/opencv…...
springboot中线程池的使用
一、概念 线程池就是将多个线程对象放入一个池子里面,例如一个池塘,线程池就是这个池塘,池塘里面的鱼就是线程池中的多个线程对象。1. 每一个线程,在一段时间内只能执行一个任务。2. 线程池中的各个线程是可以重复使用的。 二、创…...

ubuntu20.04 开机自动挂载外加硬盘
文章目录 一、问题描述二、操作1. 查找新添盘符2. 格式化硬盘文件系统3. 挂载硬盘4. 开机自动挂载5. 取消挂载6. 查看挂载的硬盘信息 一、问题描述 因电脑使用一段时间后自身硬盘不足,需外加硬盘使得电脑自动识别加载。 二、操作 1. 查找新添盘符 sudo blkid自己…...

5.18 TCP机械臂模拟
#include <netinet/tcp.h>//包含TCP选项的头文件 #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <linux/input.h>//读取输入事件 #include <sys/types.h> #include <sys/stat.h&…...

linux---线程控制
线程和进程 以前我们要同时跑多个程序,可以通过fork()多个子进程,然后通过系统函数进行程序的替换,但是创建进程代价大,不仅要拷贝一份父进程的地址空间,页表,文件表述符表等。但是线程不需要因为是进程的…...

低代码开发:拖拽式可视化构建工业物联网系统
什么是低代码? 低代码(Low Code)是一种可视化的软件开发方法,通过最少的手动编码可以更快地交付应用程序。低代码平台的图形用户界面和拖放功能可自动执行开发过程的各个方面,从而消除对传统计算机编程方法的依赖。 什么是低代码平台&#…...

【撸源码】【ThreadPoolExecutor】线程池的工作原理深度解析——上篇
1. 前言 线程池这块,作为高频面试题,并且实际使用场景巨多,所以出了这篇文章,一块来研究一下线程池的实现原理,运行机制,从底层深挖,不再局限于面试题。 2. 线程池概览 2.1. 构造器 线程池总…...
webpack 学习之 五大核心
为什么用 webpack webpack 官网传送门 … 官网:webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。总结:汇总所有模块…...
Android逆向抓包技巧 - Hook 底层通信
一,请求的本质 平时开发使用的 http 或 https 均属于应用层的协议,其本质都会调用 TCP 发送请求。 例如:你在 Python 中使用 requests 模块发送一个 http 请求,其底层就是使用 socket 模块 + TCP 实现发送的请求。 import requestsres = requests.get("http://wiki…...

深入解析力扣162题:寻找峰值(线性扫描与二分查找详解)
❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣! 推荐:数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航: LeetCode解锁100…...
模板方法及设计模式——Java笔记
模板方法及设计模式 抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。 解决的问题: 当功能内部一部分实现是确定的,另一…...

K8S认证|CKA题库+答案| 11. 创建PVC
11、创建PVC 您必须在以下Cluster/Node上完成此考题: Cluster Master node Worker node ok8s master …...

多微信如何高效管理?一台电脑就能搞定!
对于有多个微信号的人来说,管理这些微信无疑是一道难题。 今天,就给大家分享一个能够让你高效管理多个微信号的神器——个微管理系统,下面,就一起来看看它都有哪些功能吧! 1、多号同时登录在线 系统支持多个微信号同…...

安装harbor出现问题: Running 1/1 ✘ Network harbor_harbor Error
安装harbor出现问题: [] Running 1/1 ✘ Network harbor_harbor Error 0.2s failed to create network harbor_harbor: Error response from daemon: Fa…...

向 AI Search 迈进,腾讯云 ES 自研 v-pack 向量增强插件揭秘
作者:来自腾讯云刘忠奇 2025 年 1 月,腾讯云 ES 团队上线了 Elasticsearch 8.16.1 AI 搜索增强版,此发布版本重点提升了向量搜索、混合搜索的能力,为 RAG 类的 AI Search 场景保驾护航。除了紧跟 ES 官方在向量搜索上的大幅优化动…...
【vLLM 学习】Cpu Offload Lmcache
vLLM 是一款专为大语言模型推理加速而设计的框架,实现了 KV 缓存内存几乎零浪费,解决了内存管理瓶颈问题。 更多 vLLM 中文文档及教程可访问 →https://vllm.hyper.ai/ *在线运行 vLLM 入门教程:零基础分步指南 源码 examples/offline_inf…...
Lifecycle 核心原理面试回答
1. 核心目标与设计思想 解耦生命周期管理: 将 Activity/Fragment 的生命周期回调逻辑从视图控制器中剥离,让业务组件(如 Presenter, Repository 封装)能独立感知生命周期。 状态驱动: 将离散的生命周期事件 (ON_CREAT…...

基于Django开发的运动商城系统项目
运动商城系统项目描述 运动商城系统是一个基于现代Web技术构建的电子商务平台,专注于运动类商品的在线销售与管理。该系统采用前后端分离架构,前端使用Vue.js实现动态交互界面,后端基于Django框架提供RESTful API支持,数据库采用…...

1.3 古典概型和几何概型
文章目录 古典概型模型(等可能模型)几何概型 古典概型模型(等可能模型) 两个条件: 1) 有限个样本点 2) 等可能性 例题: 设有n个人,每个人都等可能地被分配到N个房间中的任一间(n≤N), 求下列事件的概率: (1)某指定的n间房…...
AI问答-vue3+ts+vite:http://www.abc.com:3022/m-abc-pc/#/snow 这样的项目 在服务器怎么部署
为什么记录有子路径项目的部署,因为,通过子路径可以区分项目,那么也就可以实现微前端架构,并且具有独特优势,每个项目都是绝对隔离的。 要将 Vue3 项目(如路径为 http://www.abc.com:3022/m-saas-pc/#/sno…...

动态规划 熟悉30题 ---上
本来是要写那个二维动态规划嘛,但是我今天在问题时候,一个大佬就把他初一时候教练让他练dp的30题发出来了(初一,啊虽然知道计算机这一专业,很多人从小就学了,但是我每次看到一些大佬从小学还是会很羡慕吧或…...
[论文阅读] 软件工程 | 如何挖掘可解释性需求?三种方法的深度对比研究
如何挖掘可解释性需求?三种方法的深度对比研究 研究背景:当软件变复杂,我们需要“说明书” 想象你买了一台智能家电,却发现它的运行逻辑完全看不懂,按钮按下后毫无反应,故障时也不提示原因——这就是现代…...

WordPress子主题RiPro-V5van无授权全开源版(源码下载)
WordPress子主题RiPro-V5van无授权全开源版,直接上使用方法:WordPress后台上传就行 这个主题是1.0版本开源的,有能力的可以二次开发一下加一些自己喜欢的功能。 源码下载:https://download.csdn.net/download/m0_66047725/90952148 更多资…...
Three.js进阶之音频处理与展示
引擎在对音频处理提供了丰富的接口,本文展示两个音频处理示例。 一、声音可视化 Three.js中的声音可视化是以视觉为核心,以音乐为载体,为音乐提供直观的视觉呈现。通过对音乐数据的分析并结合开发需求,能实现酷炫的视觉效果。在…...