Skip to content

go-zero 简介与快速开始

本篇是 go-zero 微服务框架系列教程的第一篇。我们假设你已经具备 Go 语言基础、了解过微服务的基本概念(服务注册、配置中心、限流熔断等),希望快速上手一个工程化程度高、开箱即用的微服务框架。本篇将从 go-zero 的定位讲起,介绍它的核心特性,安装官方代码生成工具 goctl,并通过一个 API 服务和一个 RPC 服务的最小示例带你跑通完整流程,最后详解 go-zero 项目结构,为后续章节打下基础。

一、go-zero 是什么

go-zero 是由好未来(TAL)学而思后端团队开源的微服务框架,使用 Go 语言编写,源码仓库托管在 GitHub:zeromicro/go-zero。它最早是为了解决好未来内部大量业务场景下的工程化、性能、稳定性问题而诞生的,经过多年生产环境打磨,于 2020 年 8 月正式开源,目前在 GitHub 上 Star 数已经稳居 Go 微服务框架前列。

go-zero 的核心理念可以总结为一句话:「工具大于约定,约定大于配置」。它通过自带的代码生成工具 goctl,把大量重复性的样板代码(路由注册、参数校验、RPC stub、类型定义、配置加载等)自动生成出来,开发者只需要在 Logic 层填业务逻辑即可。这极大降低了微服务开发的门槛,也减少了手写样板代码带来的低级错误。

1. go-zero 的定位

go-zero 不是一个单纯的 HTTP 框架(像 Gin、Echo 那样),也不是一个纯粹的 RPC 框架(像 gRPC-Go 那样),而是一套端到端的微服务开发与治理框架。它涵盖:

  • API 服务(基于 HTTP/RESTful)
  • RPC 服务(基于 gRPC)
  • 服务治理(限流、熔断、负载均衡、服务发现)
  • 数据访问(MySQL/Redis 内置封装 + 缓存)
  • 可观测性(日志、监控、链路追踪)
  • 代码生成工具(goctl)

可以把它理解成 Go 生态中接近 Spring Cloud 的角色:你不需要自己拼装一堆轮子,框架已经替你选好并组装好了。

2. 适用场景

go-zero 特别适合以下场景:

  • 中大型业务后端,需要拆分多个微服务,且对工程一致性要求高
  • 团队希望降低微服务上手成本,让新人能快速产出标准代码
  • 高并发、对延迟敏感的业务(go-zero 在性能上做了大量优化)
  • 需要完善的可观测性和服务治理能力

对于特别小型的单体应用(一两个接口),用 go-zero 会显得有些「重」,此时 Gin 这类轻量框架更合适。

二、go-zero 核心特性

1. API 服务(HTTP)

go-zero 提供了自研的 rest 包,用于构建 HTTP/RESTful 服务。它基于标准库 net/http 优化而来,支持:

  • 路由分组、前缀匹配
  • 中间件链
  • 参数解析与校验(基于 struct tag)
  • JWT 内置支持
  • 优雅退出
  • 自动 Prometheus 指标采集
  • 请求日志自动记录

rest 包的性能在 Go HTTP 框架中处于第一梯队,且 API 设计贴近工程实践。

2. RPC 服务(gRPC)

go-zero 的 RPC 服务基于 gRPC 构建,并在其上增加了:

  • 服务注册与发现(默认 etcd)
  • 客户端负载均衡(p2c 算法)
  • 自适应熔断(基于 Google SRE 算法)
  • 拦截器链
  • 链路追踪自动注入

通过 goctl,可以从 .proto 文件一键生成 RPC 服务端骨架、客户端调用代码、配置结构,开发者只需填业务逻辑。

3. 代码生成工具 goctl

goctl 是 go-zero 的「灵魂」,它是一个命令行工具,支持多种代码生成场景:

  • goctl api go:从 .api 文件生成 HTTP 服务代码
  • goctl rpc proto:从 .proto 文件生成 gRPC 服务代码
  • goctl model:从 MySQL/PostgreSQL 表结构生成数据访问层代码(含缓存)
  • goctl template:自定义模板生成代码
  • goctl kube:生成 K8s 部署文件
  • goctl docker:生成 Dockerfile

goctl 还支持模板自定义,团队可以统一代码风格,让所有人产出的代码结构一致。

4. 内置微服务治理

go-zero 内置了一套完整的服务治理能力,无需额外引入第三方库:

  • 限流:基于 Redis 的分布式限流,也支持单机限流
  • 熔断:基于 Google SRE 的自适应熔断算法(googlebreaker),根据请求成功率自动调整
  • 负载均衡:默认使用 p2c(Power of Two Choices)算法,比传统轮询更智能
  • 服务发现:内置 etcd 客户端,自动注册与发现

这些能力在框架层做了深度集成,开发者只需要在配置中开启即可。

5. 内置缓存、日志、监控

  • 缓存:go-zero 提供 sqlx + redisz + cachex 的组合,支持自动缓存(Cache-Aside),并内置 singleflight 防击穿、空值缓存防穿透
  • 日志logx 包,结构化日志,支持文件/控制台/ELK 输出,自动关联 TraceID
  • 监控:内置 Prometheus 指标采集,提供 HTTP/RPC/DB/Redis 关键指标
  • 链路追踪:内置 OpenTelemetry 支持,可与 Jaeger、Zipkin 对接

三、安装 goctl 工具

goctl 是 go-zero 的代码生成工具,是开发流程的入口。它本身是一个 Go 程序,通过 go install 安装。

1. 前置要求

确保本地已安装:

  • Go 1.18 及以上版本(推荐 1.20+)
  • 配置好 GOPATH/bin 到系统 PATH
  • 配置 Go 模块代理(国内推荐七牛或阿里云)
bash
# 配置 Go 代理(国内环境)
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct

2. 安装 goctl

bash
# 方式一:通过 go install 安装指定版本
go install github.com/zeromicro/go-zero/tools/goctl@latest

# 方式二:从源码编译
git clone https://github.com/zeromicro/go-zero.git
cd go-zero/tools/goctl
go build -o /usr/local/bin/goctl goctl.go

安装完成后验证:

bash
goctl --version
# 输出类似:goctl version 1.6.0 ...

3. 安装 protoc 与 protoc-gen-go(生成 RPC 必需)

goctl 生成 RPC 代码依赖 protoc 编译器和 Go 插件:

bash
# macOS
brew install protobuf

# Ubuntu/Debian
sudo apt install -y protobuf-compiler

# 安装 Go 插件
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

# 安装 goctl 自带的 protoc-gen-go-zero(可选,goctl rpc 会自动调用)
go install github.com/zeromicro/go-zero/tools/goctl@latest

确认 protoc 可用:

bash
protoc --version
# libprotoc 3.x.x

4. goctl 常用命令速查

bash
goctl api go -h        # 查看 api go 子命令帮助
goctl api go -api user.api -dir .  # 根据 user.api 生成 Go 代码
goctl rpc proto -h     # 查看 rpc proto 子命令帮助
goctl model mysql -h   # 查看 model 生成帮助
goctl docker -h        # 生成 Dockerfile
goctl kube -h          # 生成 K8s 部署文件
goctl template -h      # 模板管理

四、创建第一个 API 服务

我们用一个「问候」接口作为入门示例,演示从 .api 文件到运行服务的完整流程。

1. 初始化项目目录

bash
mkdir hello-api && cd hello-api
go mod init hello-api

2. 编写 .api 文件

在项目根目录创建 hello.api

api
syntax = "v1"

info (
    title:   "hello api"
    desc:    "第一个 go-zero API 服务"
    author:  "gozero-tutorial"
    version: "v1"
)

type (
    // 请求结构
    GreetRequest {
        Name string `json:"name"`
    }
    // 响应结构
    GreetResponse {
        Message string `json:"message"`
    }
)

@server (
    group: greet
    prefix: /api/v1
)
service hello-api {
    @handler GreetHandler
    post /greet (GreetRequest) returns (GreetResponse)
}

.api 文件是 go-zero 自定义的 DSL,用来描述 HTTP 服务的接口契约。关键字段含义:

  • syntax = "v1":声明 api 文件版本
  • info:元信息,用于生成文档
  • type:定义请求/响应结构体
  • @server:声明路由分组、前缀、中间件等
  • service:定义服务名、路由、handler、入参出参

3. 使用 goctl 生成代码

bash
goctl api go -api hello.api -dir . --style=goZero

参数说明:

  • -api:指定 api 文件路径
  • -dir:输出目录
  • --style:文件命名风格,支持 goZero(驼峰)、go_zero(下划线)、gozero(小写)

生成后的目录结构:

hello-api/
├── etc
│   └── hello-api.yaml         # 配置文件
├── go.mod
├── hello.api
├── hello.go                   # main 入口
├── internal
│   ├── config
│   │   └── config.go          # 配置结构体
│   ├── handler
│   │   ├── routes.go          # 路由注册
│   │   └── greet
│   │       └── greetHandler.go # handler 实现
│   ├── logic
│   │   └── greet
│   │       └── greetLogic.go  # 业务逻辑(你需要改这里)
│   ├── svc
│   │   └── serviceContext.go  # 服务上下文(依赖注入)
│   └── types
│       └── types.go           # 请求/响应结构体
└── ...

4. 编写业务逻辑

打开 internal/logic/greet/greetLogic.go,在 Greet 方法里填业务逻辑:

go
package greet

import (
    "context"
    "fmt"

    "hello-api/internal/svc"
    "hello-api/internal/types"

    "github.com/zeromicro/go-zero/core/logx"
)

type GreetLogic struct {
    logx.Logger
    ctx    context.Context
    svcCtx *svc.ServiceContext
}

func NewGreetLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GreetLogic {
    return &GreetLogic{
        Logger: logx.WithContext(ctx),
        ctx:    ctx,
        svcCtx: svcCtx,
    }
}

func (l *GreetLogic) Greet(req *types.GreetRequest) (resp *types.GreetResponse, err error) {
    name := req.Name
    if len(name) == 0 {
        name = "World"
    }
    return &types.GreetResponse{
        Message: fmt.Sprintf("Hello, %s!", name),
    }, nil
}

可以看到,go-zero 已经把路由注册、参数解析、响应序列化全部处理好了,开发者只关心 Logic 这一层。

5. 配置文件

etc/hello-api.yaml

yaml
Name: hello-api
Host: 0.0.0.0
Port: 8888

6. 运行服务

bash
# 下载依赖
go mod tidy

# 运行
go run hello.go -f etc/hello-api.yaml

看到日志输出 Starting server at 0.0.0.0:8888... 即表示启动成功。

7. 测试接口

bash
curl -X POST http://localhost:8888/api/v1/greet \
  -H "Content-Type: application/json" \
  -d '{"name":"go-zero"}'

# 响应:{"message":"Hello, go-zero!"}

至此,第一个 API 服务就跑起来了。可以看到,借助 goctl,从 .api 文件到可运行的服务只需要几秒钟。

五、创建第一个 RPC 服务

接下来演示一个 gRPC 服务。我们将创建一个 user-rpc,提供一个 getUser 方法。

1. 初始化项目

bash
mkdir hello-rpc && cd hello-rpc
go mod init hello-rpc

2. 编写 .proto 文件

创建 user.proto

proto
syntax = "proto3";

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

// 用户信息
message UserInfo {
    int64  id    = 1;
    string name  = 2;
    string email = 3;
}

// 请求
message GetUserRequest {
    int64 id = 1;
}

// 响应
message GetUserResponse {
    UserInfo user = 1;
}

service User {
    rpc GetUser(GetUserRequest) returns (GetUserResponse);
}

3. 使用 goctl 生成 RPC 代码

bash
goctl rpc protoc user.proto \
  --go_out=./pb \
  --go-grpc_out=./pb \
  --zrpc_out=. \
  --style=goZero

参数说明:

  • --go_out:protoc-gen-go 生成的 pb 文件输出目录
  • --go-grpc_out:protoc-gen-go-grpc 生成的 gRPC stub 输出目录
  • --zrpc_out:go-zero RPC 代码(server/client/logic)输出目录

生成后的目录结构:

hello-rpc/
├── etc
│   └── user.yaml              # 服务端配置
├── go.mod
├── user.proto
├── pb
│   ├── user.pb.go
│   └── user_grpc.pb.go
├── user.go                    # main 入口
├── userclient
│   └── user.go                # 客户端封装
└── internal
    ├── config
    │   └── config.go
    ├── logic
    │   └── getuserlogic.go    # 业务逻辑
    ├── server
    │   └── userserver.go      # gRPC server 实现
    ├── svc
    │   └── servicecontext.go
    └── ...

4. 编写业务逻辑

打开 internal/logic/getuserlogic.go

go
package logic

import (
    "context"

    "hello-rpc/pb"

    "github.com/zeromicro/go-zero/core/logx"
)

type GetUserLogic struct {
    ctx    context.Context
    svcCtx *svc.ServiceContext
    logx.Logger
}

func NewGetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserLogic {
    return &GetUserLogic{
        ctx:    ctx,
        svcCtx: svcCtx,
        Logger: logx.WithContext(ctx),
    }
}

func (l *GetUserLogic) GetUser(in *pb.GetUserRequest) (*pb.GetUserResponse, error) {
    // 这里演示用 mock 数据,真实场景从 DB 查询
    if in.Id <= 0 {
        return nil, fmt.Errorf("invalid user id: %d", in.Id)
    }
    return &pb.GetUserResponse{
        User: &pb.UserInfo{
            Id:    in.Id,
            Name:  fmt.Sprintf("user_%d", in.Id),
            Email: fmt.Sprintf("user_%d@example.com", in.Id),
        },
    }, nil
}

记得在文件顶部 import "fmt"

5. 配置文件

etc/user.yaml

yaml
Name: user.rpc
ListenOn: 0.0.0.0:8080

# 使用 etcd 服务注册(可选,本机调试可不配 Etcd)
Etcd:
  Hosts:
    - 127.0.0.1:2379
  Key: user.rpc

如果本地没有 etcd,可以注释掉 Etcd 配置块,go-zero 会以「直连模式」启动。

6. 运行服务

bash
go mod tidy
go run user.go -f etc/user.yaml

看到日志 Starting rpc server at 0.0.0.0:8080... 即表示启动成功。

7. 调用 RPC 服务

go-zero 生成的 userclient 包已经封装好了客户端:

go
package main

import (
    "context"
    "fmt"
    "time"

    "hello-rpc/pb"
    "hello-rpc/userclient"

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

func main() {
    client, err := zrpc.NewClient(zrpc.RpcClientConf{
        Endpoints: []string{"127.0.0.1:8080"},
        NonBlock:  true,
    })
    if err != nil {
        panic(err)
    }
    cli := userclient.NewUserClient(client.Conn())

    ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
    defer cancel()

    resp, err := cli.GetUser(ctx, &pb.GetUserRequest{Id: 100})
    if err != nil {
        panic(err)
    }
    fmt.Printf("user: %+v\n", resp.User)
}

运行后会打印:

user: id:100 name:"user_100" email:"user_100@example.com"

六、项目结构详解

go-zero 生成的项目遵循统一的目录结构,理解这个结构是后续章节的基础。

1. 整体结构

一个典型的 go-zero 单体 API 服务结构如下:

project/
├── etc/                     # 配置文件目录
│   └── project-api.yaml
├── internal/                # 内部包(不对外暴露)
│   ├── config/              # 配置结构体定义
│   ├── handler/             # HTTP handler(路由处理)
│   │   ├── routes.go        # 路由注册(goctl 生成)
│   │   └── <group>/         # 按分组组织 handler
│   │       └── xxxHandler.go
│   ├── logic/               # 业务逻辑层(重点编辑)
│   │   └── <group>/
│   │       └── xxxLogic.go
│   ├── svc/                 # ServiceContext,依赖注入容器
│   │   └── serviceContext.go
│   ├── types/               # 请求/响应类型定义
│   │   └── types.go
│   └── middleware/          # 自定义中间件(按需创建)
├── project.go               # main 入口
├── project.api              # api 定义文件(源)
├── go.mod
└── go.sum

2. 各层职责

职责是否手写
main (project.go)加载配置、启动 HTTP servergoctl 生成,一般不改
config定义配置结构体goctl 生成骨架,按需扩展
handlerHTTP 请求入口,解析参数、调用 Logic、返回响应goctl 生成,一般不改
logic业务逻辑实现goctl 生成骨架,重点手写
svcServiceContext,集中管理依赖(DB、Redis、RPC Client)goctl 生成骨架,按需扩展
types请求/响应结构体goctl 生成,不改
middleware自定义中间件手写

3. 分层调用关系

请求流转链路如下:

HTTP Request

rest.Server (路由匹配 + 中间件)

Handler (参数解析、校验)

Logic (业务逻辑,可调用 SVC 中的 DB/Redis/RPC)

Types (响应结构)

HTTP Response

核心原则:Handler 只做参数解析和响应封装,业务逻辑一律放 Logic。Logic 通过 ServiceContext 拿到依赖(DB、Redis、其他 RPC Client),实现依赖注入。

4. RPC 服务结构差异

RPC 服务结构与 API 服务类似,主要差异:

  • handler 层 → 替换为 server 层(gRPC service 实现)
  • types 层 → 由 pb 目录下的 protobuf 生成代码替代
  • 多出 userclient 包,封装客户端调用

5. main 入口解析

API 服务 main 文件示例:

go
package main

import (
    "flag"
    "fmt"

    "project/internal/config"
    "project/internal/handler"
    "project/internal/svc"

    "github.com/zeromicro/go-zero/core/conf"
    "github.com/zeromicro/go-zero/rest"
)

var configFile = flag.String("f", "etc/project-api.yaml", "the config file")

func main() {
    flag.Parse()

    var c config.Config
    conf.MustLoad(*configFile, &c)

    server := rest.MustNewServer(c.RestConf)
    defer server.Stop()

    ctx := svc.NewServiceContext(c)
    handler.RegisterHandlers(server, ctx)

    fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
    server.Start()
}

关键步骤:

  1. flag.Parse 解析命令行 -f 参数,定位配置文件
  2. conf.MustLoad 加载 YAML 配置到结构体
  3. rest.MustNewServer 创建 HTTP server
  4. svc.NewServiceContext 构建服务上下文(依赖注入)
  5. handler.RegisterHandlers 注册所有路由
  6. server.Start 启动服务(阻塞)

RPC 服务的 main 类似,把 rest.MustNewServer 换成 zrpc.MustNewServer 即可。

七、go-zero 与其他微服务框架对比

特性go-zerogo-kratosgo-microKitex(字节)
代码生成goctl,覆盖全链路工具较弱,需手动一般有代码生成
API + RPC一体化一体化主要 RPC主要 RPC
学习曲线中高
服务治理内置完整需配合第三方内置内置
缓存封装内置 CachedConn
国内资料丰富(中文社区强)较多一般较少

go-zero 的最大优势是工程化开箱即用:从 .api/.proto 到可部署的代码,几乎不需要写样板,团队协作时也容易保持一致性。

八、本机开发环境建议

为了后续章节的实战,建议本地准备以下组件:

  • Go 1.20+
  • goctl 最新版
  • MySQL 8.x(可用 Docker 启动)
  • Redis 7.x(可用 Docker 启动)
  • etcd 3.5+(用于服务注册和配置中心)
  • Jaeger(链路追踪,可选)

快速启动依赖组件的 docker-compose:

yaml
version: "3.8"
services:
  mysql:
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      MYSQL_DATABASE: "demo"
    volumes:
      - mysql-data:/var/lib/mysql
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
  etcd:
    image: bitnami/etcd:3.5
    ports:
      - "2379:2379"
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd:2379
  jaeger:
    image: jaegertracing/all-in-one:1.45
    ports:
      - "16686:16686"
      - "4318:4318"

volumes:
  mysql-data:

执行 docker-compose up -d 即可启动全部依赖。

九、小结

本篇介绍了 go-zero 的定位、核心特性,演示了 goctl 的安装与使用,并通过一个 API 服务和一个 RPC 服务的最小示例跑通了从代码生成到运行调用的完整流程。要点回顾:

  • go-zero 是端到端的微服务框架,覆盖 API/RPC/治理/可观测性
  • goctl 是开发入口,从 .api/.proto 文件自动生成标准代码
  • 项目结构分层清晰:handler → logic → svc,业务逻辑集中在 logic
  • 配置采用 YAML 文件 + 结构体的方式,简洁直观
  • API 和 RPC 的开发模式高度一致,迁移成本低

下一篇我们将深入 API 服务开发,详解 .api 文件语法、goctl api 命令、业务逻辑分层编写,并通过一个用户管理 CRUD 示例完整实践。