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

使用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 .

alt
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
alt

按提示下载,再次运行:

alt
alt
{"@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里)

alt

返回的是null,并不是预期的{"found":false,"price":0}

这是因为:

alt

resp是一个指针,这样直接return会是nil,需要如下显式声明

alt

重启服务,再次发起请求,这样的response就符合预期了~

alt

目前只返回了个空值,接下来会在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=.

alt
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=.

alt
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服务

alt

修改api/internal/config/config.go如下,增加add&check服务依赖

alt

修改api/internal/svc/servicecontext.go,如下:

alt

通过ServiceContext在不同业务逻辑之间传递依赖

(问:怎么解决依赖注入问题)


修改api/internal/logic/addlogic.go里的Add方法,如下:

alt alt

通过调用adder的Add方法实现添加图书到bookstore系统


修改api/internal/logic/checklogic.go里的Check方法,如下:

alt

通过调用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(255NOT 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 .

alt

修改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

alt

可以使用多个redis作为cache,支持redis单点或者redis集群


修改rpc/add/internal/config.go和rpc/check/internal/config.go,如下:

alt
alt

修改rpc/add/internal/svc/servicecontext.go和rpc/check/internal/svc/servicecontext.go,如下:

alt
alt

修改rpc/add/internal/logic/addlogic.go,如下

alt
alt

修改rpc/check/internal/logic/checklogic.go,如下:

alt

项目使用


需要先全部启动api服务所依赖的rpc服务。如果先启动api,则会报错:

error: context deadline exceeded, make sure rpc service "add.rpc" is already started

全部启动:

alt
alt
alt

(后面可以 -f指定不同环境的xxx.yaml)

调用add api,新增图书

curl -i "http://localhost:8888/add?book=Bible&price=10"

alt

此时看数据库,book表里新增了一行数据


调用check api,检查某本图书的价格

curl -i "http://localhost:8888/check?book=Bible"

alt
alt

重启check rpc,再次执行curl -i "http://localhost:8888/check?book=Bible"

alt

完整项目代码[2]

参考资料

[1]

使用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事务&#xff…...

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实现离线语音识别【语音助手】

背景 本系列主要目标初步完成一款智能音箱的基础功能&#xff0c;包括语音唤醒、语音识别(语音转文字)、处理用户请求&#xff08;比如查天气等&#xff0c;主要通过rasa自己定义意图实现&#xff09;、语音合成(文字转语音)功能。 语音识别、语音合成采用离线方式实现。 语…...

APT80DQ20BG-ASEMI快恢复二极管80A 200V

编辑&#xff1a;ll APT80DQ20BG-ASEMI快恢复二极管80A 200V 型号&#xff1a;APT80DQ20BG 品牌&#xff1a;ASEMI 芯片个数&#xff1a;双芯片 封装&#xff1a;TO-3P 恢复时间&#xff1a;≤50ns 工作温度&#xff1a;-55C~150C 浪涌电流&#xff1a;600A*2 正向电流…...

Go的任务调度单元与并发编程

摘要&#xff1a;本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 本文主要介绍Go语言、进程、线程、协程的出现背景原因以及Go 语言如何解决协程的…...

PDFbox教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 PDFBox是一个开源Java库&#xff0c;支持PDF文档的开发和转换.使用此库&#xff0c;您可以开发用于创建&#xff0c;转换和操作PDF文档的Java程序.除此之外&#xff0c;PDFBox还包括一个命令行实用程序&#xff0c;用于使用可用的PDF对PDF执行各种操作Jar文件. PDFB…...

Node.js-模块化理解及基本使用

模块化的定义 讲一个复杂的程序文件按照一定的规则拆分成多个独立的小文件&#xff0c;这些小文件就是小模块&#xff0c;这就是模块化。 每个小模块内部的数据是私有的&#xff0c;可以暴露内部数据给外部其他模块使用。 模块化优点 减少命名的冲突提高复用性提高可维护性按需…...

arguments 和 剩余参数

加油 &#xff01;&#xff01; &#x1f495; 文章目录 前言一、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后&#xff0c;直接在Powershell使用Docker命令 有些Developer不习惯win10系统&#xff0c;却想要使用Lin…...

Programming abstractions in C阅读笔记:p76-p83

《Programming Abstractions In C》学习第42天&#xff0c;p76-p73总结。 一、技术总结 1.数组和指针 在C语言中&#xff0c;数组和指针非常相似&#xff0c;相似到必须将它们同时考虑&#xff0c;当看到数组就应该想到指针&#xff0c;当看到指针就应该想到数组。示例&#xf…...

已解决(三个问题)|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…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...