使用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 多平台发布

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 基础篇(六)sudo和添加信任用户

一、sudo 1.是什么? 给被信任的普通用户授权,让被信任的普通用户能执行root用户才能执行的命令的一个命令。 2.为什么? 很多时候我们要在被信任的普通用户下执行一些root用户才能执行的命令,如 yum… 所以需要有一个命令能给普通用…

28 | Boss直聘数据分析

针对boss直聘网的招聘信息,然后分析互联网发展排名前十的城市在互联网方面职位的薪水,学历要求,经验要求,等等信息。 准备从以下几个方面进行分析: (1)各个城市的平均工资 (2)各个学历的平均工资 (3)各个岗位的平均工资 (4)不同工作经验要求的工资 (5)各个经验…

阿里云Windows服务器怎么安装多个网站?

本文阿里云百科介绍如何在Windows Server 2012 R2 64位系统的ECS实例上使用IIS服务器搭建多个Web站点。本教程适用于熟悉Windows操作系统,希望合理利用资源、统一管理站点以提高运维效率的用户。比如,您可以在一台云服务器上配置多个不同分类的博客平台或…

Linux 发行版 Debian 12.1 发布

导读在今年 6 月初,Debian 12“bookworm”发布,而日前 Debian 迎来了 12.1 版本,主要修复系统用户创建等多个安全问题。 Debian 是最古老的 GNU / Linux 发行版之一,也是许多其他基于 Linux 的操作系统的基础,包括 Ub…

Java内存模型

Java内存模型全称JMM(Java Memory Model) 内存主要有堆和栈组成 下面来一段demo代码详细讲解堆栈的作用,以及流程 public class Employee {private String name;private Integer age;private Department department;public Employee(){}pub…

无人驾驶实战-第十二课(强化学习自动驾驶系统)(完)

在七月算法上报了《无人驾驶实战》课程,老师讲的真好。好记性不如烂笔头,记录一下学习内容。 课程入口,感兴趣的也可以跟着学一下。 ————————————————————————————————————————— 强化学习&#xff…

ARTS 挑战打卡的第一周,我学到了这些~

目录 前言 一、学习的内容 二、超时怎么办那就换种思路看题解 三、学习打卡成果展示 3.1 Github的小技巧 3.2 英文文章阅读 3.3 一篇很不错的Java面试题博客 四、学习技巧的总结 前言 关于 ARTS 的释义 ● Algorithm: 每周至少做一个 LeetCode 的算法题 ● Review: 阅读…

Cesium相机理解

关于cesium相机,包括里面内部原理网上有很多人讲的都很清楚了,我感觉这两个人写的都挺好得: 相机 Camera | Cesium 入门教程 (syzdev.cn) Cesium中的相机—setView&lookAtTransform_cesium setview_云上飞47636962的博客-CSDN博客上面这…

微信小程序在使用vant组件库时构建npm报错

在跟着vant官方进行使用步骤一步步操作时,由于要构建NPM,但NPM包在App配置文件的外部 所以在做下图这一步时: 接着再进行npm构建时会报错 message:发生错误 Error: F:\前端学习\前端框架\小程序\project\demo\miniprogram解决方法 &#xf…

【枚举】CF1660 D

Problem - 1660D - Codeforces 题意: 思路: 思路巨简单,代码也wa了很多发才过,都是因为细节.... 很显然,要根据0分段处理 对于每一段,枚举去掉左边段还是右边段,左边段是 l 到第一个负数&am…

数据库技术--数据库引擎,数据访问接口及其关系详解(附加形象的比喻)

目录 背景数据库引擎Jet数据库:ISAM:ODBC(Open Database Connectivity): 数据访问接口ADO(ActiveX Data Objects)DAO(Data Access Objects)RDO(Remote Data O…

MySQL和钉钉单据接口对接

MySQL和钉钉单据接口对接 数据源系统:钉钉 钉钉(DingTalk)是阿里巴巴集团打造的企业级智能移动办公平台,是数字经济时代的企业组织协同办公和应用开发平台。钉钉将IM即时沟通、钉钉文档、钉闪会、钉盘、Teambition、OA审批、智能人事、钉工牌…

【小梦C嘎嘎——启航篇】内存管理小知识~

【小梦C嘎嘎——启航篇】内存管理小知识~😎 前言🙌malloc/calloc/realloc的区别?new 与 deletenew与delete要找好搭档才能保证万无一失 new 与 delete的内部实现细节是怎么样的呢???new 的内部实现细节dele…

第五次作业 运维高级 构建 LVS-DR 集群和配置nginx负载均衡

1、基于 CentOS 7 构建 LVS-DR 群集。 LVS-DR模式工作原理 首先,来自客户端计算机CIP的请求被发送到Director的VIP。然后Director使用相同的VIP目的IP地址将请求发送到集群节点或真实服务器。然后,集群某个节点将回复该数据包,并将该数据包…

Rust 编程小技巧摘选(7)

目录 Rust 编程小技巧(7) 1. 交换变量 2. 翻转数组 3. for_each() 用法 4. 结构体 Display trait 5. HashMap 和 BTreeMap 6. 遍历输出哈希表 7. 分离奇数和偶数 8. 判断素数(质数) Rust 编程小技巧(7) 1. 交换变量 与python, go等语言用法类…

第一百二十七天学习记录:我的创作纪念日

机缘 今天收到CSDN官方的来信,想想也可以对我前面的学习记录进行一个总结。 关于来到CSDN的初心,也就是为了让自己养成一个良好的学习总结的习惯。这里要感谢我C语言视频教程的老师,是他建议学生们在技术博客中进行记录。对于技术博客&…

RabbitMQ的6种工作模式

RabbitMQ的6种工作模式 官方文档: http://www.rabbitmq.com/ https://www.rabbitmq.com/getstarted.html RabbitMQ 常见的 6 种工作模式: 1、simple简单模式 1)、消息产生后将消息放入队列。 2)、消息的消费者监听消息队列,如果队列中…

从零开始学python(十六)爬虫集群部署

前言 今天讲述Python框架源码专题最后一个部分,爬虫集群部署,前面更新了十五个从零开始学python的系列文章,分别是: 1.编程语法必修篇 2.网络编程篇 3.多线程/多进程/协程篇 4.MySQL数据库篇 5.Redis数据库篇 6.MongoDB数据库篇 …

Linux:Shell编辑之文本处理器(sed)

目录 绪论 1、sed的原理:读取 执行 显示 三个过程 2、sed 文本内容处理工具,文件过大怎么办? 3、sed的操作选项 3.1 常用选项 3.2 操作符 3.3 行号的范围打印 3.4 对包含指定字符串的内容进行打印 3.5 删 3.5.1 正则表达式删除 3.6…

Vue3 Props组件简单应用(父组件获取子组件数据)

去官网学习→Props | Vue.js 运行示例&#xff1a; 代码&#xff1a;App.vue <template><img alt"Vue logo" src"./assets/logo.png"><h2>Vue Props数据传递</h2><h4>子组件中的数据&#xff1a;{{ content }}</h4>…