什么是 zrpc,怎么用

「zrpc 是 go-zero 内置的吗?怎么用?」—— 这篇把 zrpc 的身世(基于 gRPC)、它自带的服务治理、以及一条龙的使用流程(proto → goctl → server → client)讲清楚。

是什么 内置还是啥 和 gRPC 关系 使用流程 server 端 client 端 内置治理 结论

zrpc 是什么

zrpc = 「zero rpc」,是 go-zero 自带的 RPC 通信框架。它让你用 protobuf 定义接口,在服务之间高效地「远程调用方法」。

一句话:zrpc = go-zero 对 gRPC 的「开箱即用封装」。它把 gRPC 的传输能力,加上服务发现、负载均衡、超时、重试、熔断、链路追踪这些「微服务刚需」,用配置的方式一键启用——你写业务,治理交给框架。

调用方服务 user-api zrpc Client 发现+均衡+熔断 etcd 服务发现 zrpc Server user-rpc client 从 etcd 拿到 server 地址,经 gRPC 调用 超时/重试/熔断 全在 zrpc 内部自动完成

zrpc 是 go-zero 内置的吗

是。zrpc 是 go-zero 框架的一部分,包路径就是 github.com/zeromicro/go-zero/zrpc,不需要你单独引一个第三方 RPC 库。

✅ 内置 = 开箱即用
装了 go-zero 就有 zrpc。`go get github.com/zeromicro/go-zero` 后,直接 import "github.com/zeromicro/go-zero/zrpc" 即可,无需再引 grpc 包手动搭。
⚙️ 底层仍基于 gRPC
zrpc 没有重写传输层,它封装了 google.golang.org/grpc + protobuf,并在外面套了 etcd 发现、负载均衡、熔断等。所以「内置」指框架集成,不是完全另起炉灶。
📌 所以准确说法是:zrpc 是 go-zero「内置且默认推荐」的 RPC 方案,建立在 gRPC 之上。你既能用 zrpc 的封装(推荐),也能在需要时在 go-zero 项目里直接用原生 gRPC——但通常没必要。
// 只需要 go-zero,就能用 zrpc:
import (
    "github.com/zeromicro/go-zero/zrpc"        // 内置 RPC
    "google.golang.org/grpc"                 // zrpc 依赖的 gRPC(自动带)
)

zrpc 和裸 gRPC 差在哪

裸 gRPC 只管「序列化 + 传输」。微服务要的服务发现、治理,得自己拼。zrpc 把这些做成配置项。

能力裸 gRPC 自己搞zrpc(内置)
接口定义写 .proto + protoc 生成同样写 .proto,但 goctl rpc protoc 一条命令顺手把 zrpc 代码也生成了
服务发现自己接 etcd/resolver配置 Etcd: {Hosts, Key} 自动注册 + 发现
负载均衡自己选 pickerP2C(基于负载的均衡)内置
超时 / 重试手动 context + 重试逻辑Timeout / Retries 配置即用
熔断自己接 breaker客户端调用自动带熔断器
链路追踪 / 监控自行埋点otel 追踪、prometheus 指标内置,配置开启

结论:zrpc = 裸 gRPC + 一套现成的微服务治理。如果你只是「两个服务传个数据」,裸 gRPC 够用;但一旦上微服务(多个实例、要发现、要防雪崩),zrpc 的价值就出来了。

zrpc 怎么用:一条龙流程

从定义到调用,四步:写 proto → goctl 生成 → 起 server → client 调用。下面逐步给代码。

① user.proto 定义 service ② goctl 生成 stub + server 骨架 ③ 起 server 实现逻辑 + 注册 etcd ④ client 调 svc 注入即用

定义接口、生成代码、启动 server

① 写 proto

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

service User {
  rpc GetUser(GetUserReq) returns (GetUserResp);
}

message GetUserReq  { int64 id = 1; }
message GetUserResp { int64 id = 1; string name = 2; }

② goctl 一键生成(stub + server 骨架 + 配置)

goctl rpc protoc user.proto \# 生成 pb + 注册代码 + zrpc server/client
  --go_out=./types --go-grpc_out=./types \
  --zrpc_out=.

③ 启动 server(注册到 etcd)

// etc/user.yaml —— 服务端配置
Name: user.rpc
ListenOn: 0.0.0.0:8080
Etcd:
  Hosts:
    - 127.0.0.1:2379
  Key: user.rpc          # 注册到 etcd 的服务名

// internal/server/userserver.go —— goctl 生成,你只填逻辑
func (s *UserServer) GetUser(ctx context.Context, req *user.GetUserReq) (*user.GetUserResp, error) {
    u, err := s.svcCtx.DB.FindOne(ctx, req.Id)   // 业务在这里
    return &user.GetUserResp{Id: u.Id, Name: u.Name}, err
}

// main.go
func main() {
    var c config.Config
    conf.MustLoad(*configFile, &c)
    ctx := svc.NewServiceContext(c)
    s := zrpc.MustNewServer(c.RpcServerConf, func(g *grpc.Server) {
        user.RegisterUserServer(g, server.NewUserServer(ctx))  // 注册实现
    })
    defer s.Stop()
    s.Start()   // 启动后自动把 user.rpc 写进 etcd
}
📌 服务端要点:配置里写 Etcd,启动时 zrpc 自动把「服务名 → 自己的地址」注册进 etcd;客户端靠同一 Key 去 etcd 找地址。你不用手写注册/发现代码。

在另一个服务里调 zrpc

客户端同样零发现代码:配置 etcd 的 Key,goctl 生成的 user.NewUser(client) 直接拿到可调用客户端,注入 svc 即可。

// 调用方(如 user-api) 的 config:指向同一个 etcd Key
UserRpc:
  Etcd:
    Hosts:
      - 127.0.0.1:2379
    Key: user.rpc        # 和 server 端一致

// svc/servicecontext.go —— 生成客户端并注入
type ServiceContext struct {
    Config config.Config
    UserRpc user.User          # goctl 生成的客户端接口
}
func NewServiceContext(c config.Config) *ServiceContext {
    return &ServiceContext{
        Config:  c,
        UserRpc: user.NewUser(zrpc.MustNewClient(c.UserRpc)),  # ★ 创建客户端
    }
}

// logic:像调本地方法一样调远程
func (l *XxxLogic) Do() {
    resp, err := l.svcCtx.UserRpc.GetUser(l.ctx, &user.GetUserReq{Id: 1})
    # 背后:etcd 找地址 → P2C 选节点 → gRPC 调用 → 超时/重试/熔断
}

客户端三行关键:zrpc.MustNewClient(conf) 建客户端 → user.NewUser(client) 生成强类型 stub → 存进 svc。之后业务里 svcCtx.UserRpc.Xxx(ctx, req) 即可,发现、均衡、超时、重试、熔断全部透明

内置的服务治理,怎么开

zrpc 的杀手锏是「治理靠配置」。下面是最常见的几个开关(写在 yaml 里)。

⏱️ 超时 Timeout
客户端 Timeout: 3000(毫秒)。每次调用超过就中断,避免被下游拖死。
🔁 重试 Retries
客户端 Retries: 2。失败自动重试(注意下游要幂等)。
🛡️ 熔断 Breaker
客户端调用默认自带熔断器,错误率过高自动开闸保护,无需额外代码。
🔍 追踪 / 监控
配置 Telemetry 接 OpenTelemetry,Prometheus 指标自动暴露,定位跨服务问题。
# 调用方 user-api.yaml 里的 UserRpc 客户端配置示例
UserRpc:
  Etcd: { Hosts: [127.0.0.1:2379], Key: user.rpc }
  Timeout: 3000      # 超时 3s
  Retries: 1         # 失败重试 1 次
⚠️ 重试的前提是服务端接口幂等(同请求多次执行结果一致)。用户注册、扣款这类非幂等操作,开了 Retries 要特别小心,建议关掉或加幂等键。

zrpc 三问,一句话版

疑问答案
zrpc 是什么?go-zero 自带的 RPC 框架,基于 gRPC + protobuf,专用于服务间高效远程调用方法。
是 go-zero 内置的吗?是。包路径 github.com/zeromicro/go-zero/zrpc,装 go-zero 即有,无需另引 RPC 库;底层封装了 google.golang.org/grpc。
zrpc 和裸 gRPC 差啥?zrpc = 裸 gRPC + 现成治理(etcd 发现、P2C 均衡、超时、重试、熔断、追踪)。裸 gRPC 只管传输。
怎么用?四步:① 写 .proto 定义 service;② goctl rpc protoc 生成 stub+骨架;③ server 端填逻辑 + 配置 etcd 启动(自动注册);④ client 端配置同一个 etcd Key,user.NewUser(zrpc.MustNewClient(conf)) 注入 svc 后像本地方法一样调。
治理怎么开?靠配置:TimeoutRetries、内置熔断、Telemetry 追踪;重试前请确认接口幂等。

终极一句话:zrpc 就是 go-zero 内置的「gRPC + 微服务治理全家桶」。你用 protobuf 定义接口、用 goctl 生成代码,发现/均衡/超时/重试/熔断全靠配置打开——把「写 RPC」变成「填配置 + 写业务逻辑」。