一站式 Go 微服务框架:内置服务治理,开箱即用的代码生成能力。本篇先说清「框架到底给了你什么能力」,再配上可直接抄的代码示例。
go-zero 不是「又一个 Web 框架」,而是一整套「工程化 + 服务治理」的解决方案。下面这张图把它的能力分层画出来。
六大核心能力一句话说清:
go-zero 推荐「先写 .api 描述文件,再用 goctl 生成」的方式。下面三步跑通一个登录接口。
用一套极简 DSL 描述路由、入参、出参与 handler 名称。这是 go-zero 的「源代码」。
syntax = "v1" type LoginReq { Username string `json:"username"` Password string `json:"password"` } type LoginResp { Token string `json:"token"` } service user-api { @handler Login post /user/login (LoginReq) returns (LoginResp) }
一条命令生成 handler、logic、svc、路由注册与 yaml 配置。
# 生成 HTTP 服务骨架到当前目录
goctl api go -api user.api -dir .
生成后你会拿到 internal/handler/loginhandler.go、internal/logic/loginlogic.go 等文件,业务逻辑只需填在 logic 里。
func (l *LoginLogic) Login(req *types.LoginReq) (*types.LoginResp, error) { // 这里写你的业务:查库、校验密码、签发 token if req.Username == "" || req.Password == "" { return nil, errors.New("参数缺失") } token := signToken(req.Username) return &types.LoginResp{Token: token}, nil }
logic 层,handler 只做请求/响应适配,依赖(如 DB、RPC 客户端)统一放进 svc.ServiceContext。如果不想用代码生成,也能像普通 HTTP 框架那样直接写:
func main() { var c config.Config conf.MustLoad("etc/user-api.yaml", &c) server := rest.MustNewServer(c.RestConf) defer server.Stop() server.AddRoutes([]rest.Route{{ Method: http.MethodGet, Path: "/ping", Handler: func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("pong")) }, }}) server.Start() }
zrpc 基于 gRPC,但帮你把 etcd 注册发现、超时、负载均衡都默认接好了。定义 proto,生成代码,填 logic 即可。
syntax = "proto3"; package user; service User { rpc Login(LoginRequest) returns (LoginResponse); } message LoginRequest { string username = 1; string password = 2; } message LoginResponse { string token = 1; }
# 生成 RPC 代码(含 zrpc 客户端封装)
goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=.
调用端直接用生成的 client 即可,无需手写 gRPC 连接与拨号:
client := user.NewUser(zrpc.MustNewClient(c.UserRpc))
resp, err := client.Login(ctx, &user.LoginRequest{
Username: "alice",
Password: "secret",
})
防止突发流量打垮服务。go-zero 提供两种限流器,底层依赖 Redis 共享计数。
限制「每个时间窗口内最多 N 次」,适合简单配额。例:每 1 秒最多 100 次。
store := redis.NewRedis("localhost:6379", "node", "") limiter := periodlimit.New(store, 1, 100, periodlimit.Align()) code, err := limiter.Take("user:login") // code == limitallow → 放行 // code == limitover → 拒绝
平滑限流,突发可借令牌。适合对抖动敏感的场景。
limiter := tokenlimit.New(store,
tokenlimit.WithTotal(100),
tokenlimit.WithRate(10))
code, err := limiter.Take("order:create")
if code == tokenlimit.OverQuota {
return errors.New("too many requests")
}
当被调服务持续失败时,自动「断开」一段时间,避免雪崩。go-zero 用的是 Google SRE 的滑动窗口算法。
var resp *user.LoginResponse err := breaker.Do("user-rpc", func() error { var e error resp, e = client.Login(ctx, req) return e }, func(err error) { // 熔断期间或失败时的兜底逻辑 resp = &user.LoginResponse{Token: ""} }) if err != nil { return nil, err }
go-zero 的 model 层与 cache 包内置了 singleflight 与批量查询,避免缓存击穿、雪崩。
用 goctl 生成 model 时加 -c 参数即可开启缓存(基于主键的自动读写缓存)。
goctl model mysql ddl -src user.sql -dir . -c
生成的 model 在 FindOne 时会先查缓存,未命中才查库,并用 singleflight 合并并发回源。
cache := cache.NewNode("localhost:6379", "node", "", false) var name string err := cache.Get("user:1:name", &name, func(v *string) error { // 缓存未命中时回源(自动 singleflight) *v = "alice" return nil })
统一的结构化日志,直接对接 Prometheus 与告警。
logx.Info("user login success") logx.Infof("uid=%d cost=%dms", uid, cost) logx.Errorf("db query failed: %v", err) // 带字段的上下文日志 logx.WithContext(ctx).Infow("rpc call", logx.Field("method", "Login"), logx.Field("code", 0))
在 yaml 配置里打开即可暴露 /metrics,无需额外代码:
Prometheus: Host: 0.0.0.0 Port: 9091 Path: /metrics
同时框架会自动采集 QPS、耗时、熔断次数等核心指标。
鉴权、跨域、链路追踪等都通过中间件注入,不污染业务代码。
func AuthMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("Authorization") if token == "" { w.WriteHeader(http.StatusUnauthorized) return } next(w, r) } } // 注册:server.Use(AuthMiddleware)
srv := zrpc.MustNewServer(c.RpcServerConf, func(s *grpc.Server) { s.Use(func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { start := time.Now() resp, err := handler(ctx, req) logx.Infof("%s cost=%v", info.FullMethod, time.Since(start)) return resp, err }) })