自go-zero走进微服务

简介: Go-zero 的微服务进阶之路:始于 goctl 的契约驱动与提效,立于 zrpc 与 etcd 的架构互联,成于 熔断限流等全链路服务治理的坚实保障。

在我最初看来,go-zero 最核心的价值体现在两点:
1、使用 .api 定义接口协议(Contract First)
2、使用 goctl 自动生成工程骨架,让开发者专注于业务逻辑

在使用中,我发现 go-zero 的核心并不止于脚手架,
而是一整套围绕“可维护性、可扩展性”的工程化约束体系。

后来真正进入项目后,我才逐渐意识到:
RPC(zrpc + etcd)才是 go-zero 支撑微服务架构的第二个关键支点。
而中间件、熔断、限流、链路最终,是第三个核心支点

配置环境

安装 goctl(go-zero 的脚手架)

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

生成代码

方法一:

(这种方式,是直接一键生成)
等环境配置完毕后。
直接进入go编辑器,在命令行中输入!(切记是命令行)

goctl api new firstdemo

然后你就会非常完美的发现。骨架已经搭建完毕。
有了这个,大家可以非常丝滑的将一个框架搭起。

方法二:

你首先创建一个.api文件:

syntax = "v1"

info (
  title: "gozero-demo"
  desc: "first api"
  author: "you"
  version: "1.0"
)

type (
  PingReq {
   
    name string `form:"name,optional"`
  }

  PingResp {
   
    message string `json:"message"`
  }

  CreateReq {
   
    title string `json:"title"`
    content string `json:"content"`
  }

  CreateResp {
   
    id int64 `json:"id"`
  }
)

service demo-api {
   
  @handler Ping
  get /ping (PingReq) returns (PingResp)

  @handler CreatePost
  post /posts (CreateReq) returns (CreateResp)
}

我简洁的解释一下
get/ping:GET 参数通常用 form:""(对应 query)
post /posts:POST JSON 用 json:""
@handler Xxx:生成的 handler/logic 名字,也就是生成对应的router、控制器、业务层代码...

然后执行命令:

goctl api go -api demo.api -dir .
go_zero_project/
├── demo.api                  #  API 协议定义(接口契约,最核心)
│
├── demo-api.go               # 程序入口(main)
│   └── main()
│       └── 启动 HTTP Server
│
├── etc/
│   └── demo-api.yaml         # 配置文件(端口 / DB / Redis / JWT 等)
│
├── internal/
│   │
│   ├── handler/              # HTTP 层(参数 → 逻辑)
│   │   ├── pinghandler.go
│   │   └── createposthandler.go
│   │
│   ├── logic/                # 业务逻辑层(核心代码写这里)
│   │   ├── pinglogic.go
│   │   └── createpostlogic.go
│   │
│   ├── types/                # 请求 / 响应结构体(由 .api 生成)
│   │   ├── ping.go
│   │   └── createpost.go
│   │
│   └── svc/
│       └── servicecontext.go # 依赖注入(DB / Redis / RPC Client)
│
└── go.mod                    # Go Module 定义

热加载

咱们这里,先在命令行中下载:

go install github.com/air-verse/air@latest
air -v

下载完成之后,再次输入:

air

作用:

这里重点说一下 air 起到作用的3个点:

  • 监听文件变化
  • 自动 go build
  • 杀掉旧进程 → 启动新进程

实现GET/POST/PUT/DELETE

现在把目录清空。
然后新创建一个first.api的文件,并依次把下方四种不同类型的粘贴进去。

get 查询

// 获取用户
type GetUserReq {
    id int64 `form:"id"`
}

type GetUserResp {
    id   int64  `j    son:"id"`
    name string `json:"name"`
}

service demo-api {
    @handler GetUser
    get /user (GetUserReq) returns (GetUserResp)
}

post 创建

// 创建用户
type CreateUserReq {
    name string `json:"name"`
    age  int    `json:"age"`
}

type CreateUserResp {
    id int64 `json:"id"`
}

service demo-api {
    @handler CreateUser
    post /user (CreateUserReq) returns (CreateUserResp)
}

put 更新

// 更新用户
type UpdateUserReq {
    id   int64  `path:"id"`
    name string `json:"name"`
}

type UpdateUserResp {
    ok bool `json:"ok"`
}

service demo-api {
    @handler UpdateUser
    put /user/:id (UpdateUserReq) returns (UpdateUserResp)
}

delete 删除

// 删除用户
type DeleteUserReq {
    id int64 `path:"id"`
}

type DeleteUserResp {
    ok bool `json:"ok"`
}

service demo-api {
    @handler DeleteUser
    delete /user/:id (DeleteUserReq) returns (DeleteUserResp)
}

之后,运行命令:

 goctl api go -api firstdemo.api -dir .

之后,你就会得到这样一个帅气的目录,拥有基础的增删改查

动态路由

在我看来,只要仅操作一个资源的,都可以考虑用动态路由。

动态路由很简单,只需要简单的3步走即可。

  • 路由路径利用 :变量名
    get /articles/:id
    
    :id 表示这里是一个占位符
  • 请求体里用 path:"变量名"

    type GetArticleReq {
    id int64 `path:"id"`
    }
    

    切记 path:"id" 必须和 :id 一模一样!否则解析不到值。

  • method + handler 正确绑定

    @handler GetArticle
    get /articles/:id (GetArticleReq) returns (GetArticleResp)
    

    多个参数

    可能就会有人问了,多个参数了怎么办?
    简直太好办了

    GET /users/:userId/articles/:articleId
    
    type GetUserArticleReq {
    userId    int64 `path:"userId"`
    articleId int64 `path:"articleId"`
    }
    

    中间件

    1、首先你要了解什么是中间件?
    2、go-zero中的中件长什么样?
    3、如何挂在到路由上?
    4、他的职责是什么?
    请带着这些疑问来阅读接下来的内容。

    无中间件:

    一条没有中间件的访问路径大致是这样:

    HTTP Request
    ↓
    handler
    ↓
    logic
    ↓
    response
    

    但现实项目里,你经常要做些和业务无关、但每个接口都要的事:
    比如:
    1、校验登录态 / Token
    2、打日志
    3、统一鉴权(验证权限)
    4、限流(限制并发的)
    5、统计耗时
    等等...
    如果你把这些都写进 logic 或 handler,结果是:
    造成的后果,不仅是每个接口重复写、业务逻辑被污染,
    更是使后期根本维护不动!

    挂载上中间件

    中间件 = 在请求进入 handler 之前 / 返回响应之前,插一段统一逻辑。
    如下:

    HTTP Request
    ↓
    Middleware(Auth / Log / RateLimit)
    ↓
    handler
    ↓
    logic
    ↓
    response
    

    在框架中的位置

    internal/
    ├── middleware/        ← 中间件目录
    │   └── authmiddleware.go
    │
    ├── handler/           ← HTTP 参数解析
    ├── logic/             ← 业务逻辑
    ├── svc/
    │   └── servicecontext.go  ← 依赖注入(中间件从这拿资源)
    

    记住:中间件 ≠ handler ≠ logic
    它是作为一个独立层存在的。

中间件的样子

// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2

package middleware

import "net/http"

type AuthMiddleware struct {
   
}

func NewAuthMiddleware() *AuthMiddleware {
   
    return &AuthMiddleware{
   }
}

func (m *AuthMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
   
    return func(w http.ResponseWriter, r *http.Request) {
   
        // TODO generate middleware implement function, delete after code implementation

        // Passthrough to next handler if need
        next(w, r)
    }
}

如何生成?

我新建了一个文件:auth.api

syntax = "v1"

type GetUserReq {
    id int64 `path:"id"`
}

type GetUserResp {
    id int64 `json:"id"`
}

@server (
    group:      user
    middleware: Auth // 这里
)
service user-api {
    @handler GetUser
    get /users/:id (GetUserReq) returns (GetUserResp)
}

通过运行

goctl api go -api auth.api -dir .

@doc与import

@doc是什么?

@doc 是写在路由上的“接口说明元数据”,用于生成文档/让接口更可读。

@doc "获取文章详情"
@handler GetArticle
get /articles/:id (GetArticleReq) returns (GetArticleResp)

import 是什么?

当你的项目接口多了,一个 .api 文件会越来越大,变成“几千行的屎山”。
import 的作用是:
把 api 文件拆分成多个小文件,再由一个入口 api 汇总。

如下的布局方式:

api/
├── auth.api          # 入口(import 其它 api)
├── user.api          # 用户相关
└── types.api         # 公共 type(可选)

auth.api

syntax = "v1"

import "types.api"
import "user.api"

user.api

syntax = "v1"

@server(
  group: user
)

service user-api {
  @doc "获取用户详情"
  @handler GetUser
  get /users/:id (GetUserReq) returns (GetUserResp)
}

types.api

syntax = "v1"

type GetUserReq {
  id int64 `path:"id"`
}

type GetUserResp {
  id   int64  `json:"id"`
  name string `json:"name"`
}

最后命令行一生成:

 goctl api go -api auth.api -dir .

RPC服务

首先,我们要先明确:
RPC = 远程函数调用(像本地函数一样调用远程服务)
但注意!RPC 的核心不是“远程”,而是:

  • 强接口约束(proto)
  • 高性能(HTTP/2 + protobuf)
  • 面向服务而不是面向资源

在go-zero里

API 服务  ——(rpc client)——>  RPC 服务  ——>  业务逻辑 / DB

在rpc与go-zero集合的项目中,往往少不了以下这四步:
1、*.proto
→ 接口契约(定义有哪些方法、参数、返回值)

2、 goctl rpc new / protoc
→ 生成 RPC 服务骨架

3、etc/*.yaml
→ RPC 监听端口、服务名

4、internal/logic
→ 你真正写业务的地方

大家可以手动创建一个user的包,输入:

goctl rpc new

你将会得到:

user/
├── user.proto
├── user.go
├── etc/
│   └── user.yaml
├── internal/
│   ├── config/
│   ├── logic/
│   ├── server/
│   └── svc/
└── go.mod

这样一个骨架。
此时你会看到,这样一份协议

syntax = "proto3";

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

message Request {
  string ping = 1;
}

message Response {
  string pong = 1;
}

service User {
  rpc Ping(Request) returns(Response);
}

与user.go中的,启动函数。

package main

import (
    "flag"
    "fmt"

    "go_zero_project/gozero-rpc-demo/user/internal/config"
    "go_zero_project/gozero-rpc-demo/user/internal/server"
    "go_zero_project/gozero-rpc-demo/user/internal/svc"
    "go_zero_project/gozero-rpc-demo/user/user"

    "github.com/zeromicro/go-zero/core/conf"
    "github.com/zeromicro/go-zero/core/service"
    "github.com/zeromicro/go-zero/zrpc"
    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
)

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

func main() {
   
    flag.Parse()

    var c config.Config
    conf.MustLoad(*configFile, &c)
    ctx := svc.NewServiceContext(c)

    s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
   
        user.RegisterUserServer(grpcServer, server.NewUserServer(ctx))
        if c.Mode == service.DevMode || c.Mode == service.TestMode {
   
            reflection.Register(grpcServer)
        }
    })
    defer s.Stop()

    fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
    s.Start()
}

请你点开的小手。
在终端中输入go mod tidy,更新拉取一下。
run一下,即可启动!

什么?你说你运行失败了?

etcd

如果运行失败了,大概率是 etcd 尚未启动,这是新手最常见的问题之一。
因为你没有安装etdc。

什么是etdc?
etcd 你可以将其当成一个高可用的分布式 KV 存储(Key-Value),核心用途在微服务里是:
服务发现:服务启动把自己的地址写进去(注册)
配置中心/开关:把配置、feature flag 放进去
分布式协调:租约、锁、选主....
如果你是第一次接触 etcd,可以先“功能上”把它理解为:

一个专门给微服务用的「注册中心 / 配置中心」

!!但要注意:

  • etcd ≠ Redis
  • etcd 具有强一致(Raft)
  • Redis 更偏缓存、高吞吐

一、下载

https://github.com/etcd-io/etcd/releases

二、配置
把你含有以下,两个文件的cmd路径,配置到全局PATH路径内。

 - etcd.exe
 - etcdctl.exe

三、运行
直接在cmd内,输入以下四个英文单词。

etcd

启动!
四、检测

netstat -ano | findstr :2379

看一看是否在监听!
此时,你在回去运行一下项目,自然就跑通了。
五、为什么要用这个?
这是很多人的疑惑!
看etc内的配置文件:

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

小傻蛋们,因为配置文件用到了etcd。

调用rpc服务

初步调用

首先启动服务。

之后在apifox中操作的,创建基于grpc的接口管理!
(当然你换成其他也操作函数)
然后把我的.proto文件放置进去。
在user.User /Ping接口上,点击调用。

{
   
    "pong": "hello"
}

修改

插入这些,
然后在,service User 里加一条:
方法名:GetUser
请求:GetUserRequest
响应:GetUserResponse
并新增 2 个 message:
GetUserRequest { int64 id = 1; }
GetUserResponse { int64 id = 1; string name = 2; }

syntax = "proto3";

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

message Request {
  string ping = 1;
}

message Response {
  string pong = 1;
}

message GetUserRequest {
  int64 id = 1;
}
message GetUserResponse {
  int64 id = 1;
  string name = 2;
}

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

最关键的一步:

goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=.

同个这个,生成rpc代码框架。
这里就是微服务中,被远程调用部分。
也是go-zero中的,两个最重要的核心之一!
而另一个就是api,也就是对外!同时调用rpc的部分!

API

其实这个主要就两个步骤

一、生成 API 项目骨架

(一般,新启一个项目时用)

goctl api new userapi

二、写 .api 协议后生成代码

(更新项目时使用)

goctl api go -api userapi.api -dir .

其实api还有很多组件需要掌握:
gorm、auth、jwt...
但是这些其实都与gin框架大差不差。

这次就先记录到这里,如果想要了解更多、更详细的,可以直接到官网了解,文档写的还是非常简洁通透的:
go-zero文档

目录
相关文章
|
1天前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
10128 27
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
13天前
|
人工智能 安全 Linux
【OpenClaw保姆级图文教程】阿里云/本地部署集成模型Ollama/Qwen3.5/百炼 API 步骤流程及避坑指南
2026年,AI代理工具的部署逻辑已从“单一云端依赖”转向“云端+本地双轨模式”。OpenClaw(曾用名Clawdbot)作为开源AI代理框架,既支持对接阿里云百炼等云端免费API,也能通过Ollama部署本地大模型,完美解决两类核心需求:一是担心云端API泄露核心数据的隐私安全诉求;二是频繁调用导致token消耗过高的成本控制需求。
5847 14
|
21天前
|
人工智能 JavaScript Ubuntu
5分钟上手龙虾AI!OpenClaw部署(阿里云+本地)+ 免费多模型配置保姆级教程(MiniMax、Claude、阿里云百炼)
OpenClaw(昵称“龙虾AI”)作为2026年热门的开源个人AI助手,由PSPDFKit创始人Peter Steinberger开发,核心优势在于“真正执行任务”——不仅能聊天互动,还能自动处理邮件、管理日程、订机票、写代码等,且所有数据本地处理,隐私完全可控。它支持接入MiniMax、Claude、GPT等多类大模型,兼容微信、Telegram、飞书等主流聊天工具,搭配100+可扩展技能,成为兼顾实用性与隐私性的AI工具首选。
22881 119
|
7天前
|
人工智能 JavaScript API
解放双手!OpenClaw Agent Browser全攻略(阿里云+本地部署+免费API+网页自动化场景落地)
“让AI聊聊天、写代码不难,难的是让它自己打开网页、填表单、查数据”——2026年,无数OpenClaw用户被这个痛点困扰。参考文章直击核心:当AI只能“纸上谈兵”,无法实际操控浏览器,就永远成不了真正的“数字员工”。而Agent Browser技能的出现,彻底打破了这一壁垒——它给OpenClaw装上“上网的手和眼睛”,让AI能像真人一样打开网页、点击按钮、填写表单、提取数据,24小时不间断完成网页自动化任务。
1723 4