使用go-zero快速构建微服务
本文是对 使用go-zero快速构建微服务[1]的亲手实践
编写API Gateway代码
mkdir bookstore && cd bookstore
go mod init bookstore
mkdir api && goctl api -o api/bookstore.api
syntax = "v1"info(title: "xx使用go-zero"desc: "xx用来上手go-zero"author: "xxxx"email: "xxxx@gmail.com"
)type (addReq struct {book string `form:"book"`price int64 `form:"price"`}addResp struct {ok bool `json:"ok"`}
)type (checkReq struct {book string `form:"book"`}checkResp struct {found bool `json:"found"`price int64 `json:"price"`}
)service bookstore-api {@handler AddHandlerget /add (addReq) returns (addResp)@handler CheckHandlerget /check (checkReq) returns (checkResp)
}
cd api && goctl api go -api bookstore.api -dir .
api
├── bookstore.api // api定义
├── bookstore.go // main入口定义
├── etc
│ └── bookstore-api.yaml // 配置文件
└── internal
├── config
│ └── config.go // 定义配置
├── handler
│ ├── addhandler.go // 实现addHandler
│ ├── checkhandler.go // 实现checkHandler
│ └── routes.go // 定义路由处理
├── logic
│ ├── addlogic.go // 实现AddLogic
│ └── checklogic.go // 实现CheckLogic
├── svc
│ └── servicecontext.go // 定义ServiceContext
└── types
└── types.go // 定义请求、返回结构体
go run bookstore.go -f etc/bookstore-api.yaml
启动API Gateway服务,默认侦听在8888端口
因为默认生成的api/etc/bookstore-api.yml为:
Name: bookstore-api
Host: 0.0.0.0
Port: 8888
按提示下载,再次运行:
{"@timestamp":"2023-02-16T16:31:09.658+08:00","caller":"stat/usage.go:61","content":"CPU: 0m, MEMORY: Alloc=2.5Mi, TotalAlloc=2.5Mi, Sys=14.5Mi, NumGC=0","level":"stat"}
{"@timestamp":"2023-02-16T16:31:09.662+08:00","caller":"load/sheddingstat.go:61","content":"(api) shedding_stat [1m], cpu: 0, total: 0, pass: 0, drop: 0","level":"stat"}
{"@timestamp":"2023-02-16T16:31:15.044+08:00","caller":"stat/metrics.go:210","content":"(bookstore-api) - qps: 0.0/s, drops: 0, avg time: 0.0ms, med: 0.0ms, 90th: 0.0ms, 99th: 0.0ms, 99.9th: 0.0ms","level":"stat"}
会定时(默认一分钟)输出cpu,内存等的统计信息,可以通过 logx.DisableStat()禁用 (可以做到自定义模板.tpl里)
返回的是null,并不是预期的{"found":false,"price":0}
这是因为:
resp是一个指针,这样直接return会是nil,需要如下显式声明
重启服务,再次发起请求,这样的response就符合预期了~
目前只返回了个空值,接下来会在rpc服务里实现业务逻辑
可以修改internal/svc/servicecontext.go来传递服务依赖(如果需要,比如Config,Auth,后续用到的RPC等)
实现逻辑可以修改internal/logic下的对应文件(如果接口较多,可以在.api里定义不同的group,使用goctl生成代码时,会自动在logic下根据group名称创建不同的文件夹)
可以通过goctl生成各种客户端语言的api调用代码(供客户端同学使用;支持多种语言)
编写RPC代码
编写add rpc服务
切到bookstore目录下
mkdir -p rpc/add && cd rpc/add
goctl rpc template -o add.proto
修改后文件内容如下:
syntax = "proto3";package add;option go_package = "./pb";message addReq {string book = 1;int64 price = 2;
}message addResp {bool ok = 1;
}service adder {rpc add(addReq) returns(addResp);
}
goctl rpc protoc add.proto --go_out=./pb --go-grpc_out=./pb --zrpc_out=.
rpc/add
├── add.go // rpc服务main函数
├── add.proto // rpc接口定义
├── adder
│ ├── adder.go // 提供了外部调用方法,无需修改
│ ├── adder_mock.go // mock方法,测试用
│ └── types.go // request/response结构体定义
├── etc
│ └── add.yaml // 配置文件
├── internal
│ ├── config
│ │ └── config.go // 配置定义
│ ├── logic
│ │ └── addlogic.go // add业务逻辑在这里实现
│ ├── server
│ │ └── adderserver.go // 调用入口, 不需要修改
│ └── svc
│ └── servicecontext.go // 定义ServiceContext,传递依赖
└── pb
└── add.pb.go
go run add.go -f etc/add.yaml 可运行该服务
默认每隔一分钟输出cpu和内存信息
{"@timestamp":"2023-02-16T20:02:10.640+08:00","caller":"stat/usage.go:61","content":"CPU: 0m, MEMORY: Alloc=3.3Mi, TotalAlloc=6.2Mi, Sys=15.9Mi, NumGC=3","level":"stat"}
{"@timestamp":"2023-02-16T20:02:10.656+08:00","caller":"load/sheddingstat.go:61","content":"(rpc) shedding_stat [1m], cpu: 0, total: 0, pass: 0, drop: 0","level":"stat"}
编写check rpc服务
切到bookstore目录下
mkdir -p rpc/check && cd rpc/check
goctl rpc template -o check.proto
修改后文件内容如下:
syntax = "proto3";package check;option go_package = "./pb";message checkReq {string book = 1;
}message checkResp {bool found = 1;int64 price = 2;
}service checker {rpc check(checkReq) returns(checkResp);
}
goctl rpc protoc check.proto --go_out=./pb --go-grpc_out=./pb --zrpc_out=.
rpc/check
├── check.go // rpc服务main函数
├── check.proto // rpc接口定义
├── checker
│ ├── checker.go // 提供了外部调用方法,无需修改
│ ├── checker_mock.go // mock方法,测试用
│ └── types.go // request/response结构体定义
├── etc
│ └── check.yaml // 配置文件
├── internal
│ ├── config
│ │ └── config.go // 配置定义
│ ├── logic
│ │ └── checklogic.go // check业务逻辑在这里实现
│ ├── server
│ │ └── checkerserver.go // 调用入口, 不需要修改
│ └── svc
│ └── servicecontext.go // 定义ServiceContext,传递依赖
└── pb
└── check.pb.go
go run check.go -f etc/check.yaml 可运行该服务
修改etc/check.yaml的端口为8081(因为8080已经被add服务使用了)
再回去修改API Gateway代码,调用add/check rpc服务
api/etc/bookstore-api.yaml,增加如下内容
Add:
Etcd:
Hosts:
- localhost:2379
Key: add.rpc
Check:
Etcd:
Hosts:
- localhost:2379
Key: check.rpc
通过etcd自动去发现可用的add和check服务
修改api/internal/config/config.go如下,增加add&check服务依赖
修改api/internal/svc/servicecontext.go,如下:
通过ServiceContext在不同业务逻辑之间传递依赖
(问:怎么解决依赖注入问题)
修改api/internal/logic/addlogic.go里的Add方法,如下:

通过调用adder的Add方法实现添加图书到bookstore系统
修改api/internal/logic/checklogic.go里的Check方法,如下:
通过调用checker的Check方法实现从bookstore系统中查询图书的价格
定义数据库表结构,并生成CRUD+cache代码
bookstore下创建rpc/model目录
mkdir -p rpc/model (不过一般习惯把这个model文件夹抽出来,和api,rpc在一层)
在rpc/model目录下编写创建book表的sql文件book.sql,如下:
CREATE TABLE `book`
(
`book` varchar(255) NOT NULL COMMENT 'book name',
`price` int NOT NULL COMMENT 'book price',
PRIMARY KEY(`book`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
进入mysql命令行,创建DB和table
create database gozero;
source book.sql;
在rpc/model目录下执行如下命令生成CRUD+cache代码,-c表示使用redis cache
goctl model mysql ddl -c -src book.sql -dir .
修改add rpc和check rpc,调用crud+cache代码
修改rpc/add/etc/add.yaml和rpc/check/etc/check.yaml,均增加如下内容:
DataSource: root:123456@@tcp(xxx.xxx.xx.xx:3306)/gozero
#DataSource: root:123456@@tcp(localhost:3306)/gozero?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai #可以这样指定一些其他信息
Table: book
Cache:
- Host: localhost:6379
可以使用多个redis作为cache,支持redis单点或者redis集群
修改rpc/add/internal/config.go和rpc/check/internal/config.go,如下:
修改rpc/add/internal/svc/servicecontext.go和rpc/check/internal/svc/servicecontext.go,如下:
修改rpc/add/internal/logic/addlogic.go,如下
修改rpc/check/internal/logic/checklogic.go,如下:
项目使用
需要先全部启动api服务所依赖的rpc服务。如果先启动api,则会报错:
error: context deadline exceeded, make sure rpc service "add.rpc" is already started
全部启动:
(后面可以 -f指定不同环境的xxx.yaml)
调用add api,新增图书
curl -i "http://localhost:8888/add?book=Bible&price=10"
此时看数据库,book表里新增了一行数据
调用check api,检查某本图书的价格
curl -i "http://localhost:8888/check?book=Bible"
重启check rpc,再次执行curl -i "http://localhost:8888/check?book=Bible"
完整项目代码[2]
参考资料
使用go-zero快速构建微服务: http://www.jikejiaocheng.com/c/gozero-microservices.html
[2]完整项目代码: https://github.com/cuishuang/bookstore
本文由 mdnice 多平台发布
相关文章:
使用go-zero快速构建微服务
本文是对 使用go-zero快速构建微服务[1]的亲手实践 编写API Gateway代码 mkdir bookstore && cd bookstorego mod init bookstore mkdir api && goctl api -o api/bookstore.api syntax "v1"info(title: "xx使用go-zero"desc: "xx用…...
Java开发 - Redis事务怎么用?
前言 最近博主感觉捅了Redis窝,从Redis主从,哨兵,集群,集群原理纷纷讲了一遍,不知道大家都学会了多少,想着送佛送到西,不如再添一把火,所以今天带给大家的博客是Redis事务ÿ…...
Windows Server 2019安装使用PostgreSQL 15
主要是参考这篇文章来做的: Windows11安装配置PostgreSQL(图文详细教程)_win11安装postgres 并管理工具_return strxi的博客-CSDN博客 1. 下载的是postgresql 15.3 windows x64-86版本 Community DL Page 2. 安装时一定要右击安装exe文件…...
中科驭数亮相DPU峰会,分享HADOS软件生态实践和大数据计算方案,再获评“匠芯技术奖”
又是一年相逢时,8月4日,第三届DPU峰会在北京开幕,本届峰会由中国通信学会指导,江苏省未来网络创新研究院主办,SDNLAB社区承办,以“智驱创新芯动未来”为主题,沿袭技术创新、生态协同的共创效应&…...
chrome、edge、Firefox关闭音量提醒控件显示
文章目录 1. Chrome2. edge3. firefox 1. Chrome 在地址栏输入: chrome://flags/#hardware-media-key-handling 将Hardware Media Key Handling的状态设为Disabled 2. edge 在地址栏输入 edge://flags/#hardware-media-key-handling 将Hardware Media Key Handling的状态…...
3.7v升压5v4A芯片用什么型号
问:我需要一个能够将3.7V锂电池的电压升压到5V,并且能够提供4A的电流输出的芯片。请问有什么推荐的型号吗? 答:小编为您推荐AH6922B芯片,它具备以下特点来满足您的需求: 1. 输入电压范围适配:…...
鉴源实验室丨SOME/IP协议安全攻击
作者 | 张昊晖 上海控安可信软件创新研究院工控网络安全组 来源 | 鉴源实验室 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 01 引 言 随着汽车行业对于数据通信的需求不断增加,SOME/IP作为支持汽车以太网进程和设备间通信的一种通信协议应…...
什么?200?跨域?
情景复现 今天我遇到了一件很奇怪的事情就是,当我请求后端网关,然后通过网关去请求相应的服务,都进行了跨域处理 但是,奇怪的是我在请求的时候,回来的响应码是200,但是报错了,报的还是200的同…...
【数据结构与算法——TypeScript】算法的复杂度分析、 数组和链表的对比
【数据结构与算法——TypeScript】 算法的复杂度分析 什么是算法复杂度(现实案例)? ❤️🔥 前面已经解释了什么是算法? 其实就是解决问题的一系列步骤操作、逻辑。 ✅ 对于同一个问题,我们往往有很多种解决思路和方法&#x…...
搜索综合训练
搜索综合训练 选数详细注释的代码 小木棍详细注释的代码 费解的开关详细注释的代码 选数 详细注释的代码 #include <iostream> #include <vector>using namespace std;// 判断一个数是否为素数 bool isPrime(int num) {if (num < 1)return false;// 判断从2到s…...
snowboy+新一代kaldi(k2-fsa)sherpa-onnx实现离线语音识别【语音助手】
背景 本系列主要目标初步完成一款智能音箱的基础功能,包括语音唤醒、语音识别(语音转文字)、处理用户请求(比如查天气等,主要通过rasa自己定义意图实现)、语音合成(文字转语音)功能。 语音识别、语音合成采用离线方式实现。 语…...
APT80DQ20BG-ASEMI快恢复二极管80A 200V
编辑:ll APT80DQ20BG-ASEMI快恢复二极管80A 200V 型号:APT80DQ20BG 品牌:ASEMI 芯片个数:双芯片 封装:TO-3P 恢复时间:≤50ns 工作温度:-55C~150C 浪涌电流:600A*2 正向电流…...
Go的任务调度单元与并发编程
摘要:本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 前言 本文主要介绍Go语言、进程、线程、协程的出现背景原因以及Go 语言如何解决协程的…...
PDFbox教程_编程入门自学教程_菜鸟教程-免费教程分享
教程简介 PDFBox是一个开源Java库,支持PDF文档的开发和转换.使用此库,您可以开发用于创建,转换和操作PDF文档的Java程序.除此之外,PDFBox还包括一个命令行实用程序,用于使用可用的PDF对PDF执行各种操作Jar文件. PDFB…...
Node.js-模块化理解及基本使用
模块化的定义 讲一个复杂的程序文件按照一定的规则拆分成多个独立的小文件,这些小文件就是小模块,这就是模块化。 每个小模块内部的数据是私有的,可以暴露内部数据给外部其他模块使用。 模块化优点 减少命名的冲突提高复用性提高可维护性按需…...
arguments 和 剩余参数
加油 !! 💕 文章目录 前言一、arguments二、arguments转成array三、箭头函数不绑定arguments四、剩余参数 ... 前言 其实在es6之后不推荐使用 arguments , 建议使用剩余参数 一、arguments arguments 是一个 对应于 传递给函数的参数 的 类数…...
【BASH】回顾与知识点梳理(十二)
【BASH】回顾与知识点梳理 十二 十二. Linux 文件与目录管理12.1 目录与路径相对路径与绝对路径相对路径的用途绝对路径的用途 12.2 目录的相关操作cd (change directory, 变换目录)pwd (Print Working Directory, 显示目前所在的目录)mkdir (make directory, 建立新目录)rmdir…...
本地构建包含java和maven的镜像
目录 1.前提条件 2.下载 2.1.创建Dockerfile 3.构建镜像 参考文章 1.前提条件 本地环境需要的系统和软件 win10 Docker Desktop Powershell 图1 Win10安装Docker后,直接在Powershell使用Docker命令 有些Developer不习惯win10系统,却想要使用Lin…...
Programming abstractions in C阅读笔记:p76-p83
《Programming Abstractions In C》学习第42天,p76-p73总结。 一、技术总结 1.数组和指针 在C语言中,数组和指针非常相似,相似到必须将它们同时考虑,当看到数组就应该想到指针,当看到指针就应该想到数组。示例…...
已解决(三个问题)|neo4j Failed authentication attempt for ‘meter‘ from 127.0.0.1
问题1 py2neo.errors.ConnectionUnavailable: Connection has been closed 问题2 neo4j Failed authentication attempt for ‘meter’ from 127.0.0.1 问题3 py2neo.errors,ClientError: [Security.Unauthorized] Invalid username or password. 作者:xiao黄 博客地址:http…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...
【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
sshd代码修改banner
sshd服务连接之后会收到字符串: SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢? 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头,…...
