依旧推荐官方文档: 快速开始指南

安装

安装 goctl

go install github.com/zeromicro/go-zero/tools/goctl@latest

安装完成后在你的 ${GOPATH}/bin 目录下会有一个 goctl.exe 文件, 执行 goctl --version 出现版本信息即安装成功 (如果出现类似于找不到命令的报错的话, 那么需要将 ${GOPATH}/bin 目录添加到环境变量中)

PS D:\goprojects> goctl --version
goctl version 1.5.4 windows/amd64

安装工具包

goctl env check --install --verbose --force

这里可能会因为某些原因安装失败, 如果是 windows 系统的话, 那可以直接在 这里 下载压缩包, 下载完成后只需要将压缩包中的文件夹移到 ${GOPATH} 目录下即可

其他系统的话可以选择手动安装三个工具:

protoc 需要前往 github 下载安装包, 然后同样直接把安装包里面的文件放到你的 ${GOPATH} 目录下即可

# proto-gen-go-grpc
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# protoc-gen-go
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

安装完成后进行验证

PS D:\goprojects> goctl env check --verbose
[goctl-env]: preparing to check env

[goctl-env]: looking up "protoc"
[goctl-env]: "protoc" is installed

[goctl-env]: looking up "protoc-gen-go"
[goctl-env]: "protoc-gen-go" is installed

[goctl-env]: looking up "protoc-gen-go-grpc"
[goctl-env]: "protoc-gen-go-grpc" is installed

[goctl-env]: congratulations! your goctl environment is ready!

安装 gozero

在一个有 go mod 的项目下执行 go get 获取 gozero

$ mkdir usercenter && cd usercenter
$ go mod init usercenter
$ go get -u github.com/zeromicro/go-zero@latest

如果报错的话可能是因为没有开启 gomod 或者是网络问题:

$ go env -w GO111MODULE=on # 开启 gomod 模式
$ go env -w GOPROXY=https://goproxy.cn,direct # 设置代理

单体服务写法

编写 api 文件

gozero 是根据 api 文件 来生成代码, 所以我们使用上面生成的 usercenter 项目, 并写一个简单的 api demo

usercenter 目录下新建 api 目录, 在 api 目录中新建 user.api 文件, 写入以下内容

syntax = "v1"

info(
	title: "Usercenter API"
	desc: "API for usercenter"
	author: "GuoChenxu"
	email: "2269409349@qq.com"
	version: "1.0"
)

// 定义数据结构
type (
	PingReq {
		Id int64 `path:"id"`
	}
	PingResp {
		Pong string `json:"string"`
	}
)

// 这里定义了路径前缀, 此外还可以定义jwt 开关、中间件、路由分组、路由前缀等
// server 对下面 service 中的所有服务有效
@server(
	prefix: user
)

// 定义具体的服务请求路径
service user {
	@doc "ping"
	@handler ping
	get /ping/:id (PingReq) returns (PingResp)
}

参数的 tag 和传参形式的对应:

tag 传参形式
path Path 传参
form Query 传参
json Body 传参

生成代码

在 api 文件所在目录下生成代码

# --api 指定 api 文件
# --dir 指定生成代码目录
# --style 指定命名风格
PS D:\goprojects\src\usercenter\api> goctl api go --api .\user.api --dir .\ --style=go_zero
Done.

注意, 有些同学 比如我 用了 gowork 管理项目, 那么在生成代码之前需要将项目加到 gowork 文件中 具体代码如下:

# .\src\ 是你的项目目录
go work use -r .\src\

现在的文件目录如下:

D:\GOPROJECTS\SRC\USERCENTER
│  go.mod
│  go.sum
└─api
    │  user.api  # api 文件
    │  user.go   # 项目入口文件
    ├─etc
    │      user.yaml   # 配置文件
    └─internal
        ├─config
        │      config.go   # 读取配置
        ├─handler   # 路由
        │      ping_handler.go
        │      routes.go
        ├─logic   # 核心逻辑
        │      ping_logic.go
        ├─svc   # 上下文
        │      service_context.go
        └─types   # 项目中的数据结构
                types.go

编写逻辑代码

gozero 的魅力在于他几乎生成了所有其他的代码, 你只需要关注最核心的逻辑代码

打开 internal/logic/ping_logic.go 开始编写代码

func (l *PingLogic) Ping(req *types.PingReq) (resp *types.PingResp, err error) {
	id := strconv.FormatInt(req.Id, 10)
	return &types.PingResp{
		Pong: "pong: " + id,
	}, nil
}

运行项目

PS D:\goprojects\src\usercenter\api> go run .\user.go
Starting server at 0.0.0.0:8888...

因为默认的 json 格式日志不好看, 所以我们在 etc/user.yaml 中修改日志格式

Name: user
Host: 0.0.0.0
Port: 8888

Log:
    Encoding: plain

成功响应:

日志打印:

至此一个简单的单体 demo 就写完了

rpc 服务写法

编写 proto 文件

与 api 文件类似, rpc 是根据 proto 文件 生成代码

usercenter 目录下新建 rpc 目录, 在 rpc 目录中新建 user.proto 文件, 写入以下功能

syntax = "proto3";

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

// 定义消息类型
message Request {
  int64 id = 1;
}

message Response {
  string Pong = 1;
}

// 定义服务
service userrpc {
  rpc Ping(Request) returns(Response);
}

生成代码

在 proto 文件目录下生成代码

# protoc 指定 proto文件
# *_out  指定代码文件的输出目录
PS D:\goprojects\src\usercenter\rpc> goctl rpc protoc .\user.proto --go_out=.\ --go-grpc_out=.\ --zrpc_out=.\ --style=go_zero
Done.

文件目录

D:\GOPROJECTS\SRC\USERCENTER
│  go.mod
│  go.sum
├─api
└─rpc
    │  user.go
    │  user.proto
    ├─etc
    │      user.yaml
    ├─internal
    │  ├─config
    │  │      config.go
    │  │
    │  ├─logic
    │  │      ping_logic.go
    │  │
    │  ├─server
    │  │      userrpc_server.go
    │  │
    │  └─svc
    │          service_context.go
    ├─pb
    │      user.pb.go
    │      user_grpc.pb.go
    └─userrpc
            userrpc.go

安装 etcd

rpc 默认生成的代码是使用 etcd 注册发现服务的, 所以还需要安装 etcd

前往 github 下载合适的版本, 解压后放在合适的目录下, 并添加进环境变量

验证安装成功

PS D:\Tools\etcd> etcd --version
etcd Version: 3.5.9
Git SHA: bdbbde998
Go Version: go1.19.9
Go OS/Arch: windows/amd64

启动 etcd

如果你在尝试了 下载最新版本、使用管理员权限运行、启动端口没有被占用、关闭防火墙 之后仍旧无法正常启动 etcd, 那么请重启电脑后再次运行

编写逻辑代码

编写 rpc 目录下的 internal/logic/ping_logic.go

func (l *PingLogic) Ping(in *pb.Request) (*pb.Response, error) {
	id := strconv.FormatInt(in.Id, 10)
	return &pb.Response{
		Pong: "pong: " + id,
	}, nil
}

运行项目

修改一下项目的运行端口, etcd 的监听地址和 log 格式

Name: user.rpc
ListenOn: 0.0.0.0:8889
Etcd:
    Hosts:
        - 0.0.0.0:2379
    Key: user.rpc

Log:
    Encoding: plain

运行项目

单独测试 rpc 服务

你可以对每个 rpc 服务都写一个客户端进行测试, 但是这样过于繁琐, 所以我们希望可以单独对 rpc 服务进行测试

这里推荐 apifox (最新版), 可以像 http 接口一样测试 rpc 服务

  1. 点击新建项目, 选择新建 gRpc 项目

  2. 点击左上角加号, 直接导入 proto 文件

  3. 然后就可以像普通的 http 接口一样发送请求进行测试

测试成功

单体项目升级成微服务

在编写了 rpc 服务之后, 我们可以将之前的 api 单体服务升级成微服务项目

服务发现

现在下述操作均在 api 目录下执行

打开 etc/user.yaml 增加如下配置

Name: user
Host: 0.0.0.0
Port: 8888

Log:
    Encoding: plain

# 客户端 etcd 配置
UserRpcConfig:
    Etcd:
        Hosts:
            - 127.0.0.1:2379
        Key: user.rpc

internal/config/config.go 文件中增加配置

package config

import (
	"github.com/zeromicro/go-zero/rest"
	"github.com/zeromicro/go-zero/zrpc"
)

type Config struct {
	rest.RestConf
	UserRpcConfig zrpc.RpcClientConf   // 读取 rpc 配置
}

internal/svc/service_context.go 文件中增加代码

package svc

import (
	"usercenter/api/internal/config"
	"usercenter/rpc/userrpc"

	"github.com/zeromicro/go-zero/zrpc"
)

type ServiceContext struct {
	Config        config.Config
	UserRpcClient userrpc.Userrpc   // 注册 rpc 客户端
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config:        c,
		UserRpcClient: userrpc.NewUserrpc(zrpc.MustNewClient(c.UserRpcConfig)),
	}
}

至此客户端的服务发现已经配置完成

修改核心代码

升级成微服务后就要将逻辑代码交给 rpc 服务端去做, 客户端需要给服务端发送请求, 所以需要修改核心的逻辑代码

修改 api 目录下的 internal/logic/ping_logic.go 文件

func (l *PingLogic) Ping(req *types.PingReq) (resp *types.PingResp, err error) {
    // 向服务端发送请求
	pong, err := l.svcCtx.UserRpcClient.Ping(l.ctx, &userrpc.Request{
		Id: req.Id,
	})
	return &types.PingResp{
		Pong: pong.GetPong(),
	}, err
}

运行项目

先运行服务端, 再运行客户端

测试成功

查看日志, 确实是服务端接受请求并处理

至此 gozero 的快速入门就结束了, 后续会有文章讲述 在 gozero 中使用 gorm, gozero 的 api 文件编写 以及 在 gozero 中使用 nacos 进行服务的注册发现等 咕咕咕, 先立个 flag

参考文章

快速开始

指南