← 返回文章列表

Go-Zero 微服务框架

学习 go-zero 的框架结构与服务开发流程。

go

简介

go-zero是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。

go-zero 包含极简的 API 定义和生成工具 goctl,可以根据定义的 api 文件一键生成 Go, iOS, Android, Kotlin, Dart, TypeScript, JavaScript 代码,并可直接运行。

go-zero框架能轻松获得支撑千万日活服务的稳定性,内建级联超时控制、限流、自适应熔断、自适应降载等微服务治理能力,无需配置和额外代码,微服务治理中间件可无缝集成到其它现有框架使用,极简的 API 描述,一键生成各端代码,自动校验客户端请求参数合法性,大量微服务治理和并发工具包。

go-zero框架具有强大的工具支持,尽可能少的代码编写,极简的接口,完全兼容 net/http,支持中间件,方便扩展,高性能,面向故障编程,弹性设计,内建服务发现、负载均衡,内建限流、熔断、降载,且自动触发,自动恢复,API 参数自动校验,超时级联控制,自动缓存控制,链路跟踪、统计报警等,高并发支撑,稳定保障了疫情期间每天的流量洪峰。

下面是官方给的架构图

go

安装和快速使用

安装

这里主要是go-zero、goctl和go-zero的安装指令,可以参照官方的文档:快速开始

注意先安装go,关于go的安装和配置可以见博客:g的安装和使用

# go-zero安装
go get -u github.com/zeromicro/go-zero@latest
# goctl安装
go install github.com/zeromicro/go-zero/tools/goctl@latest
# protoc安装
goctl env check --install --verbose --force

go

快速使用

Api demo

在这里我创建了一个文件夹GoZeroDemo存放go-zero微服务框架学习期间的相关代码,之后初始化项目,并使用gpctl自动生成简单API相关文件

# 创建并进入项目
mkdir GoZeroDemo && cd GoZeroDemo
# 初始化项目并命名
go mod init gozerodemo
# 使用goctl创建API服务
goctl api new greet
# 安装缺失的依赖
go mod tidy

下面是生成的代码框架,包括配置文件、main文件、配置定义文件、网络路由相关文件、请求逻辑文件、业务逻辑相关文件以及业务相关结构体文件等等。

go

之后我们根据官方说明,在greetlogic.go中实现Greet,做简单的 Say Hello,测试效果如下,一个简单的单体服务就构建完成了。

go

通过简单的使用go-zero我们可以发现,框架的作用就是帮你生成配套代码,你只需要完成相应的业务逻辑。

gRPC demo

继续在GoZeroDemo目录下创建gRPC服务aorange

# 使用goctl创建RPC服务
goctl rpc new aorange
# 安装缺失的依赖
go mod tidy

go

之后按照文档进行简单修改测试:gRPC-demo

go

MySQL

创建sql文件,之后通过goctl生成对应的golang文件和操作方法,具体参考:mysql代码生成

goctl model mysql ddl --src user.sql --dir .

go

Mongo

mongo 不像 mysql 一样有建表语句,索引等集中有规律的约束信息,因此 mongo 代码的生成无需类似 sql 或者数据库链接一样的信息。,具体参考:mongo代码生成

goctl model mongo --type user --dir .

go

format

还可以通过goctl进行格式化,具体见:api文件格式化

goctl api format --dir demo.api

Goctl

下面是goctl相关的指令和说明,我们常用的就是api和rpc

go

Api

go

参考官方给的api示例,我们使用goctl通过api文件创建服务

首先创建项目文件夹添加user.api

之后在终端输入指令

goctl api go -api user.api -dir . -style goZero
syntax = "v1"

type (
        // 定义登录接口的 json 请求体
        LoginReq {
                Username string `json:"username"`
                Password string `json:"password"`
        }
        // 定义登录接口的 json 响应体
        LoginResp {
                Id       int64  `json:"id"`
                Name     string `json:"name"`
                Token    string `json:"token"`
                ExpireAt string `json:"expireAt"`
        }
)

type (
        // 定义获取用户信息的 json 请求体
        GetUserInfoReq {
                Id int64 `json:"id"`
        }
        // 定义获取用户信息的 json 响应体
        GetUserInfoResp {
                Id   int64  `json:"id"`
                Name string `json:"name"`
                Desc string `json:"desc"`
        }
        // 定义更新用户信息的 json 请求体
        UpdateUserInfoReq {
                Id   int64  `json:"id"`
                Name string `json:"name"`
                Desc string `json:"desc"`
        }
)

// 定义 HTTP 服务
// @server 语法块主要用于控制对 HTTP 服务生成时 meta 信息,目前支持功能有:
// 1. 路由分组
// 2. 中间件声明
// 3. 路由前缀
// 4. 超时配置
// 5. jwt 鉴权开关
// 所有声明仅对当前 service 中的路由有效
@server (
        // 代表当前 service 代码块下的路由生成代码时都会被放到 login 目录下
        group: login
        // 定义路由前缀为 "/v1"
        prefix: /v1
)
// 微服务名称为 user,生成的代码目录和配置文件将和 user 值相关
service user {
        // 定义 http.HandleFunc 转换的 go 文件名称及方法,每个接口都会跟一个 handler
        @handler login
        // 定义接口
        // 请求方法为 post
        // 路由为 /user/login
        // 请求体为 LoginReq
        // 响应体为 LoginResp,响应体必须有 returns 关键字修饰
        post /user/login (LoginReq) returns (LoginResp)
}

// @server 语法块主要用于控制对 HTTP 服务生成时 meta 信息,目前支持功能有:
// 1. 路由分组
// 2. 中间件声明
// 3. 路由前缀
// 4. 超时配置
// 5. jwt 鉴权开关
// 所有声明仅对当前 service 中的路由有效
@server (
        // 代表当前 service 代码块下的所有路由均需要 jwt 鉴权
        // goctl 生成代码时会将当前 service 代码块下的接口
        // 信息添加上 jwt 相关代码,Auth 值为 jwt 密钥,过期
        // 等信息配置的 golang 结构体名称
        jwt: Auth
        // 代表当前 service 代码块下的路由生成代码时都会被放到 user 目录下
        group: user
        // 定义路由前缀为 "/v1"
        prefix: /v1
)
// 注意,定义多个 service 代码块时,服务名称必须一致,因此这里的服务名称必须
// 和上文的 service 名称一样,为 user 服务。
service user {
        // 定义 http.HandleFunc 转换的 go 文件名称及方法,每个接口都会跟一个 handler
        @handler getUserInfo
        // 定义接口
        // 请求方法为 post
        // 路由为 /user/info
        // 请求体为 GetUserInfoReq
        // 响应体为 GetUserInfoResp,响应体必须有 returns 关键字修饰
        post /user/info (GetUserInfoReq) returns (GetUserInfoResp)

        // 定义 http.HandleFunc 转换的 go 文件名称及方法,每个接口都会跟一个 handler
        @handler updateUserInfo
        // 定义接口
        // 请求方法为 post
        // 路由为 /user/info/update
        // 请求体为 UpdateUserInfoReq
        // 由于不需要响应体,因此可以忽略不写
        post /user/info/update (UpdateUserInfoReq)
}

go

RPC

go

rpc采用同样的方式

相关指令和代码如下:

goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=.
// 声明 proto 语法版本,固定值
syntax = "proto3";

// proto 包名
package greet;

// 生成 golang 代码后的包名
option go_package = "example/proto/greet";

// 定义枚举

enum Status{
  UNSPECIFIED = 0;
  SUCCESS = 1;
  FAILED = 2;
}

// 定义结构体

message Base{
  int32 code = 1;
  string msg = 2;
}

message SendMessageReq{
  string message = 1;
}

message SendMessage{
  // 使用枚举
  Status status = 1;
  // 数组
  repeated string array = 2;
  // map
  map<string,int32> map = 3;
  // 布尔类型
  bool boolean = 4;
  // 序列号保留
  reserved 5;
}

message SendMessageResp{
  Base base = 1;
  SendMessage data = 2;
}

// 定义 Greet 服务
service Greet {
  // 定义客户端流式 rpc
  rpc SendMessage(stream SendMessageReq) returns (SendMessageResp);
}

go

Model

go

以SQL为例,创建sql文件,通过下面指令生成相关代码

goctl model mysql ddl -src"./user.sql" -dir="./sql/model" -c

go

参考资料

go-zero

go-zero官方文档

go的版本管理工具-g的安装和使用

关于这篇文章的日期

旧日期 2025-01-16 与文章发布记录不符,现按旧站可确认的首次发布日 2026-01-21 整理。实际创作日期尚无法确认。