2. 初识go-zero

发布于:2025-03-25 ⋅ 阅读:(36) ⋅ 点赞:(0)

介绍

go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。
go-zero 中的 api,rpc,数据库等涉及的代码,都可以给我们一键生成,无需耗费我们什么精力
只需要在生成的代码中填入自己的配置以及逻辑即可。

go-zero 框架具有以下显著特点:
强大的工具支持:尽可能少的代码编写**,通过 goctl 工具一键生成多端代码**。
极简的接口:完全兼容 net/http,支持中间件,方便扩展。
高性能:面向故障编程,弹性设计,内建服务发现、负载均衡、限流、熔断、降载等微服务治理能力。
自动校验:API 参数自动校验,超时级联控制,自动缓存控制。
链路跟踪:统计报警等,稳定保障了疫情期间每天的流量洪峰。
在这里插入图片描述

  • 基本功能层面

    • 并发控制 & 限流,避免服务被突发流量击垮
    • 服务注册与服务发现,确保能够动态侦测增减的节点
    • 负载均衡,需要根据节点承受能力分发流量
    • 超时控制,避免对已超时请求做无用功
    • 熔断设计,快速失败,保障故障节点的恢复能力
  • 高阶功能层面

    • 请求认证,确保每个用户只能访问自己的数据
    • 链路追踪,用于理解整个系统和快速定位特定请求的问题
    • 日志,用于数据收集和问题定位
    • 可观测性,没有度量就没有优化

短链微服务架构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

配置相关环境

  1. 安装etcd(高可用的分布式键值存储系统)工具 https://github.com/etcd-io/etcd/releases(用于 服务发现(Service Discovery);消息发布与订阅;负载均衡;分布式通知与协调;分布式锁)
  2. 安装protoc工具
    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
  3. 安装goctl工具
    go install github.com/zeromicro/go-zero/tools/goctl@latest

使用示例

单RPC服务

  1. 创建工作目录 shorturl shorturl/api
  2. 在shorturl/api 目录下运行指令 goctl api -o shorturl.api
  3. 编辑 api/shorturl.api
syntax = "v1"

info (
	title: "go-zero rpc demo"
	desc: "单rpc的go-zero使用demo"
	author: "why151"
	email: "1758592354@qq.com"
)

type expandReq {
	shorten string `form:"shorten"`
}

type expandRes {
	url string `json:"url"`
}

type(
	shortenReq{
		url string `form:"url"`
	}
	shortenRes{
		url string `json:"shorten"`
	}
)



// 定义服务名字
service shorturl-api {
	// 定义了服务端 handler 名字
	@handler ShortenHandler
	// 定义了 get 方法的路由、请求参数、返回参数等
	get /shorten(shortenReq) returns(shortenRes)

	@handler ExpandHandler
	post /expand(expandReq) returns(expandRes)
}

  1. 在 shorturl/api目录下运行指令 goctl api go -api shorturl.api -dir .
    生成的文件结构如下:
    ├── api
    │ ├── etc
    │ │ └── shorturl-api.yaml // 配置文件
    │ ├── internal
    │ │ ├── config
    │ │ │ └── config.go // 定义配置
    │ │ ├── handler
    │ │ │ ├── expandhandler.go // 实现 expandHandler
    │ │ │ ├── routes.go // 定义路由处理
    │ │ │ └── shortenhandler.go // 实现 shortenHandler
    │ │ ├── logic
    │ │ │ ├── expandlogic.go // 实现 ExpandLogic
    │ │ │ └── shortenlogic.go // 实现 ShortenLogic
    │ │ ├── svc
    │ │ │ └── servicecontext.go // 定义 ServiceContext
    │ │ └── types
    │ │ └── types.go // 定义请求、返回结构体
    │ ├── shorturl.api
    │ └── shorturl.go // main 入口定义
    ├── go.mod
    └── go.sum
  2. 运行 go mod tidy 整理依赖
  3. 启动 API Gateway 服务,默认侦听在 8888 端口
    go run shorturl.go -f etc/shorturl-api.yaml
  4. 测试 API Gateway 服务
    curl -i “http://localhost:8888/shorten?url=https://go-zero.dev”
    在这里插入图片描述
  5. 在 shorturl目录下创建 rpc/transform 目录
  6. 通过 goctl rpc -o transform.proto 生成proto文件模板
  7. 修改文件结构
syntax = "proto3";

package transform;
option go_package="./transform";

message expandReq{
  string shorten = 1;
}

message expandRes{
  string url = 1;
}

message shortenReq{
  string url = 1;
}

message shortenRes{
  string shorten = 1;
}

service Transform {
  rpc expand(expandReq) returns(expandRes);
  rpc shorten(shortenReq) returns(shortenRes);
} 

  1. 利用下列指令生成rpc结构
    goctl rpc protoc transform.proto --go_out=. --go-grpc_out=. --zrpc_out=.

文件结构如下:

rpc/transform
├── etc
│ └── transform.yaml // 配置文件
├── internal
│ ├── config
│ │ └── config.go // 配置定义
│ ├── logic
│ │ ├── expandlogic.go // expand 业务逻辑在这里实现
│ │ └── shortenlogic.go // shorten 业务逻辑在这里实现
│ ├── server
│ │ └── transformerserver.go // 调用入口, 不需要修改
│ └── svc
│ └── servicecontext.go // 定义 ServiceContext,传递依赖
├── transform
│ ├── transform.pb.go
│ └── transform_grpc.pb.go
├── transform.go // rpc 服务 main 函数
├── transform.proto
└── transformer
└── transformer.go // 提供了外部调用方法,无需修改

  1. 启动etcd server
  2. 启动rpc服务
    go run transform.go -f etc/transform.yaml
  3. 查看服务是否注册
    在这里插入图片描述
  4. 修改 API Gateway 代码调用 transform rpc 服务
  • 修改配置文件 shorturl-api.yaml, 新增下列内容,通过 etcd 自动去发现可用的 transform 服务
Transform:
  Etcd:
    Hosts:
      - localhost:2379
    Key: transform.rpc
  • 修改 shorturl/api/internal/config/config.go 如下,增加 transform 服务依赖
type Config struct {
  rest.RestConf
  Transform zrpc.RpcClientConf     // 手动代码
}
  • 修改 shorturl/api/internal/svc/servicecontext.go,如下:
type ServiceContext struct {
  Config    config.Config
  Transformer transformer.Transformer                                          // 手动代码
}

func NewServiceContext(c config.Config) *ServiceContext {
  return &ServiceContext{
    Config:    c,
    Transformer: transformer.NewTransformer(zrpc.MustNewClient(c.Transform)),  // 手动代码
  }
}

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

  • 修改 shorturl/api/internal/logic/expandlogic.go 里的 Expand 方法,如下:
func (l *ExpandLogic) Expand(req types.ExpandReq) (types.ExpandResp, error) {
  // 手动代码开始 
  rpcResp, err := l.svcCtx.Transformer.Expand(l.ctx, &transformer.ExpandReq{
      Shorten: req.Shorten,
  })
  if err != nil {
      return nil, err
  }

  return &types.ExpandResp{
      Url: rpcResp.Url,
  }, nil
    // 手动代码结束
}

通过调用 transformer 的 Expand 方法实现短链恢复到 url

  • 修改 shorturl/api/internal/logic/shortenlogic.go,如下:
func (l *ShortenLogic) Shorten(req types.ShortenReq) (types.ShortenResp, error) {
  // 手动代码开始
  rpcResp, err := l.svcCtx.Transformer.Shorten(l.ctx, &transformer.ShortenReq{
      Url: req.Url,
  })
  if err != nil {
      return nil, err
  }

  return &types.ShortenResp{
      Shorten: rpcResp.Shorten,
  }, nil
  // 手动代码结束
}

通过调用 transformer 的 Shorten 方法实现 url 到短链的变换

  1. 定义数据库表结构,并生成 CRUD+cache 代码
  • shorturl 下创建 rpc/transform/model 目录:mkdir -p rpc/transform/model

  • 在 rpc/transform/model 目录下编写创建 shorturl 表的 sql 文件 shorturl.sql,如下:

CREATE TABLE `shorturl`
(
  `shorten` varchar(255) NOT NULL COMMENT 'shorten key',
  `url` varchar(255) NOT NULL COMMENT 'original url',
  PRIMARY KEY(`shorten`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

在 mysql-server 的 go-zero 数据库下新增如上表结构

  • 在 rpc/transform/model 目录下执行如下命令生成 CRUD+cache 代码,-c 表示使用 redis cache

goctl model mysql ddl -c -src shorturl.sql -dir .

生成后的文件结构如下:

rpc/transform/model
├── shorturl.sql
├── shorturlmodel.go // 扩展代码
├── shorturlmodel_gen.go // CRUD+cache 代码
└── vars.go // 定义常量和变量

  1. 修改 shorten/expand rpc 代码调用 crud+cache 代码
  • 修改 rpc/transform/etc/transform.yaml,增加如下内容:
DataSource: root:password@tcp(localhost:3306)/gozero # 用户名和密码为你本地 mysql-server 密码,并非完全一致
Table: shorturl
Cache:
  - Host: localhost:6379
可以使用多个 redis 作为 cache,支持 redis 单点或者 redis 集群
  • 修改 rpc/transform/internal/config/config.go,如下:
type Config struct {
  zrpc.RpcServerConf
  DataSource string             // 手动代码
  Table      string             // 手动代码
  Cache      cache.CacheConf    // 手动代码
}

增加了 mysql 和 redis cache 配置

  • 修改 rpc/transform/internal/svc/servicecontext.go,如下:
type ServiceContext struct {
  c     config.Config
  Model model.ShorturlModel   // 手动代码
}
func NewServiceContext(c config.Config) *ServiceContext {
  return &ServiceContext{
    c:             c,
    Model: model.NewShorturlModel(sqlx.NewMysql(c.DataSource), c.Cache), // 手动代码
  }
}
  • 修改 rpc/transform/internal/logic/expandlogic.go,如下:
func (l *ExpandLogic) Expand(in *transform.ExpandReq) (*transform.ExpandResp, error) {
  // 手动代码开始
  res, err := l.svcCtx.Model.FindOne(l.ctx,in.Shorten)
  if err != nil {
    return nil, err
  }

  return &transform.ExpandResp{
    Url: res.Url,
  }, nil
  // 手动代码结束
}
  • 修改 rpc/transform/internal/logic/shortenlogic.go,如下:
func (l *ShortenLogic) Shorten(in *transform.ShortenReq) (*transform.ShortenResp, error) {
  // 手动代码开始,生成短链接
  key := hash.Md5Hex([]byte(in.Url))[:6]
  _, err := l.svcCtx.Model.Insert(l.ctx,&model.Shorturl{
    Shorten: key,
    Url:     in.Url,
  })
  if err != nil {
    return nil, err
  }

  return &transform.ShortenResp{
    Shorten: key,
  }, nil
  // 手动代码结束
}
  1. 在 shorturl 目录下执行 go mod tidy 整理依赖
  • 重新依次启动 redis-server,etcd-server,mysql-server, rpc 服务

  • etcd,redis,mysql 自行根据找教程安装启动

  • 启动 rpc 服务

cd rpc/transform
go run transform.go -f etc/transform.yaml
  • 新开终端启动 api 服务
cd api
go run shorturl.go -f etc/shorturl-api.yaml
  • shorten api 调用
    新开终端调用
curl -i "http://localhost:8888/shorten?url=https://go-zero.dev"

返回如下:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Traceparent: 00-fe81053320bb99d1d924021a110765bd-fa915fae41db454d-00
Date: Thu, 10 Aug 2023 03:32:05 GMT
Content-Length: 20

{"shorten":"b0434f"}%
  • expand api 调用
    shorten 值为上一步返回的值为准,每个人返回的值不一样
curl -i "http://localhost:8888/expand?shorten=b0434f"

返回如下:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Traceparent: 00-0b11aab486c47a35586d6ed08236afb2-b12387d8cc1e3508-00
Date: Thu, 10 Aug 2023 03:32:54 GMT
Content-Length: 29

{"url":"https://go-zero.dev"}%

多RPC服务

书店微服务架构图
在这里插入图片描述

  1. 生成api结构
  2. 生成 add check 两个 rpc结构
  3. 生成model结构
  4. 为api配置rpc服务(通过etcd自动去发现可用的服务依赖)
Add:
  Etcd:
    Hosts:
      - localhost:2379
  	Key: add.rpc

Check:
  Etcd:
    Hosts:
      - localhost:2379
  	Key: check.rpc
  1. 配置config增加服务依赖
type Config struct {
	rest.RestConf
	Add zrpc.RpcClientConf
	Check zrpc.RpcClientConf
}

  1. 修改servicecontext.go 在不同业务逻辑之间传递依赖
type ServiceContext struct {
	Config config.Config
	Add adder.Adder
	Check checker.Checker
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config: c,
		Add: adder.NewAdder(zrpc.MustNewClient(c.Add)),
		Check: checker.NewChecker(zrpc.MustNewClient(c.Check)),
	}
}

  1. 为RPC服务增加mysql 和 redis 配置
DataSource: root:root@tcp(192.168.145.10:3306)/gozero
Table: book
Cache:
  - Host: 192.168.145.10:6379
type Config struct {
	zrpc.RpcServerConf
	DataSource string
	Table string
	Cache cache.CacheConf
}
  1. 实现rpc的logic函数代码
  2. api调用rpc方法
  3. 验证
    在这里插入图片描述