go-zero中api和rpc服务类型选择取决于通信协议与调用方:对外暴露给前端、app或第三方系统用api(http/rest),内部强一致性、跨语言或低延迟场景选rpc(grpc)。

go-zero 不是“又一个 Web 框架”,它是微服务开发的工程化底盘——选它,不是为了写得快,而是为了上线稳、扩容顺、排查清。
goctl 生成代码时,api 和 rpc 两种服务类型怎么选?
别凭感觉,看通信协议和调用方:内部服务间强一致性要求高、需跨语言或低延迟,选 rpc;对外暴露给前端、App 或第三方系统,用 api(HTTP/REST)。
-
api生成的是 RESTful 服务,自带参数校验、Swagger 文档、中间件钩子(如AuthInterceptor),适合边界层 -
rpc默认基于 gRPC,生成.proto文件 + 客户端 stub,天然支持流式、超时透传、服务发现集成,但调用方必须能处理 protobuf - 混合架构常见:API 网关用
api,后端订单、用户等核心服务用rpc,网关里用rpcx.Client或grpc.Dial调用 - 注意:
goctl rpc生成的 client 默认不带重试逻辑,生产环境需手动封装或用rpcx的Retry中间件
连接 TiDB 时,gorm.Open 的 DSN 和连接池参数怎么设才不翻车?
TiDB 不是 MySQL 的“平替”,它的连接模型更敏感——连错一个参数,轻则慢查询,重则集群抖动。
- DNS 必须加
parseTime=true&loc=Asia%2FShanghai,否则时间字段解析失败,错误信息是invalid time format -
SetMaxOpenConns(50)是安全起点,TiDB 单节点建议 ≤100;SetMaxIdleConns(20)避免空闲连接堆积导致 TiDBtidb_max_server_connections耗尽 - 务必启用
SetConnMaxLifetime(30 * time.Second),TiDB 的连接空闲超时默认是 60s,不设此值会导致大量connection refused - 不要用
gorm.Open(mysql.Open(dsn), &gorm.Config{...})直接初始化,先建*sql.DB再传给 GORM,方便后续插桩监控
在 logic 层调用多个 rpc 服务时,如何避免 goroutine 泄漏和超时传染?
go-zero 的 ctx 是链路生命线,不是装饰品。没管好上下文,一个慢接口就能拖垮整个请求链。
- 永远用
ctx, cancel := context.WithTimeout(r.Context(), time.Second*3)包裹每个 RPC 调用,而不是复用 handler 传入的原始ctx - cancel() 必须 defer 执行,否则超时后 goroutine 仍会运行到底——这是最常被忽略的泄漏点
- 多个 RPC 并发调用,用
errgroup.Group统一管理,而非裸写go func() { ... }(),否则错误无法聚合、超时无法统一中断 - 如果某个 RPC 服务不可用,它的超时不应影响主流程,考虑用
fallback返回兜底数据,而不是让整个logic失败
部署时 etc/user-api.yaml 配置项哪些不能照抄模板?
配置文件里的注释不是摆设,是血泪教训的浓缩。照搬模板等于把测试环境的炸弹埋进生产。
-
Port必须改:K8s Service 默认只暴露 80/443,实际 Pod 端口建议固定为8888或9999,避免冲突 -
Redis的Host不能写localhost:6379—— 在容器里这指向自己,不是 Redis Pod;要用 K8s Service 名,如redis-svc:6379 -
Etcd或Nacos地址必须用 DNS 可解析的域名,不能写127.0.0.1或私有 IP,否则 sidecar 注入后无法注册 -
Log的Mode生产环境必须设为file,console模式在 K8s 里会导致日志丢失(stdout buffer 问题)
go-zero 的“开箱即用”只针对骨架,真正的稳定性藏在每一个 context.WithTimeout、每一行 DSN 参数、每一次配置项校验里。框架不会替你做决策,但它把决策路径和代价标得足够清楚。











