gRPC 客户端
gRPC 客户端
Section titled “gRPC 客户端”zrpc.Client 是 go-zero 的 gRPC 客户端封装,自动集成服务发现、P2C 负载均衡、熔断器和 OpenTelemetry 链路追踪。
方案 A:直连(开发 / 测试)
Section titled “方案 A:直连(开发 / 测试)”import ( "github.com/zeromicro/go-zero/zrpc" "myservice/greeter" // 生成的 proto 包)
func NewServiceContext(c config.Config) *ServiceContext { conn, err := zrpc.NewClient(zrpc.RpcClientConf{ Endpoints: []string{"localhost:8080"}, }) if err != nil { log.Fatal(err) } return &ServiceContext{ Config: c, GreeterClient: greeter.NewGreeterClient(conn.Conn()), }}方案 B:通过 etcd 服务发现(生产环境)
Section titled “方案 B:通过 etcd 服务发现(生产环境)”GreeterRpc: Etcd: Hosts: - 127.0.0.1:2379 Key: greeter.rpc Timeout: 2000 # 请求超时(毫秒) KeepaliveTime: 20000func NewServiceContext(c config.Config) *ServiceContext { return &ServiceContext{ Config: c, GreeterClient: greeter.NewGreeterClient( zrpc.MustNewClient(c.GreeterRpc).Conn(), ), }}MustNewClient 启动阶段出错时会 panic。如需自行处理错误,请使用 NewClient。
func (l *HelloLogic) Hello(req *types.HelloReq) (*types.HelloResp, error) { resp, err := l.svcCtx.GreeterClient.SayHello(l.ctx, &greeter.SayHelloReq{ Name: req.Name, }) if err != nil { return nil, err } return &types.HelloResp{Message: resp.Message}, nil}l.ctx 携带 OpenTelemetry trace context,下游 RPC span 会自动关联到父级 HTTP span。
GreeterRpc: # 方案一:etcd 服务发现 Etcd: Hosts: [127.0.0.1:2379] Key: greeter.rpc
# 方案二:静态地址 Endpoints: - 127.0.0.1:8080
Timeout: 2000 # 客户端请求超时(毫秒),0 表示不限 KeepaliveTime: 20000 # gRPC keepalive ping 间隔(毫秒)gRPC 错误携带状态码,go-zero 熔断器会统计这些状态:
import "google.golang.org/grpc/status"
resp, err := l.svcCtx.GreeterClient.SayHello(l.ctx, req)if err != nil { st, _ := status.FromError(err) switch st.Code() { case codes.NotFound: return nil, errorx.NewCodeError(404, "用户不存在") case codes.DeadlineExceeded: return nil, errorx.NewCodeError(504, "上游超时") default: return nil, err }}熔断器默认开启。10 秒内错误率超过 50% 时自动打开:
正常: 请求 → RPC 调用 → 响应断开: 请求 → 立即返回 503(不发 RPC)半开: 允许单个探测请求通过以检查恢复情况每个 zrpc.Client 自动生效,无需额外配置。
向每次请求注入自定义元数据(如 API Token、用户 ID):
conn, err := zrpc.NewClient(c.GreeterRpc, zrpc.WithUnaryClientInterceptor(func( ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption, ) error { ctx = metadata.AppendToOutgoingContext(ctx, "x-request-id", requestIDFromCtx(ctx), ) return invoker(ctx, method, req, reply, cc, opts...) }),)