
gRPC 在 Go 中不是开箱即用的微服务框架,它只提供 RPC 通信能力;要构建可用的微服务,必须自己补全服务发现、负载均衡、健康检查、配置管理等能力。
定义 .proto 文件时必须显式启用 go_package 选项
不写 go_package 会导致生成的 Go 代码包路径与实际目录结构不一致,import 失败或引用到错误包。常见错误现象是编译报 undefined: pb.XxxServiceClient 或 cannot find package "xxx"。
- 必须在
.proto文件顶部添加:syntax = "proto3"; option go_package = "github.com/yourorg/yourrepo/pb"; -
go_package值应与你运行protoc时的--go_out输出路径一致,且需匹配模块路径(go.mod中的 module 名) - 避免使用相对路径(如
./pb)或空字符串,这会让protoc-gen-go推导出不可控的包名
服务端启动时需同时注册 HealthServer 并监听 /healthz
Kubernetes、Consul 等平台依赖健康端点做探活,但 gRPC 默认不暴露 HTTP 健康接口。直接用 grpc.HealthCheckService 注册后,仍需额外启动一个 HTTP server 转发 /healthz 请求到 gRPC health check 逻辑。
- 先调用
health.RegisterHealthServer(grpcServer, health.NewServer()) - 再起一个独立的
http.Server,用grpc_health_v1.NewHealthClient(conn)主动调用Check()实现 HTTP 健康响应 - 不要复用 gRPC 监听端口跑 HTTP(gRPC-Web 除外),HTTP/2 和 HTTP/1.1 混合容易触发连接复用冲突
客户端连接必须设置 WithTransportCredentials 或 WithInsecure
忽略传输层配置会导致连接失败,典型错误是 connection error: desc = "transport: Error while dialing dial tcp: operation was canceled" 或长时间卡在 DialContext。
立即学习“go语言免费学习笔记(深入)”;
- 本地开发用
grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials())) - 生产环境必须用
grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)),且tlsConfig.ServerName需与证书 SAN 匹配 - 禁用
WithInsecure后未配 TLS 会直接 panic,错误信息为credentials: no credentials available
流式 RPC 的 context 生命周期极易出错
客户端取消 context 不等于服务端立即停止发送,服务端若继续写入已关闭的 stream,会触发 rpc error: code = Canceled desc = context canceled 或 write: broken pipe。
- 服务端每次
Send()前必须检查stream.Context().Err() != nil - 客户端读取
Recv()时需用if err == io.EOF { break }判断流结束,不能只靠err != nil - 不要在流处理 goroutine 中直接传入原始请求
context,应基于它派生带超时的子 context 控制单次 Send/Recv
真正难的不是写通第一个 gRPC 服务,而是让多个服务在不同网络条件下稳定互调——超时传递、deadline 透传、错误码映射、重试策略这些细节,往往比协议定义本身更消耗调试时间。










