
微服务间调用必须带超时和重试
Go 默认的 http.Client 不设超时,一次卡死就拖垮整个请求链。生产环境里,下游服务延迟抖动、瞬时不可用太常见,不控制超时等于主动放弃可用性。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 所有
http.Client必须显式设置Timeout(建议 3–5s),并单独配Transport的IdleConnTimeout和MaxIdleConnsPerHost - 重试不能无脑上 —— 只对幂等接口(如
GET、PUT)做 2 次以内指数退避重试;POST类操作必须由业务层决定是否重试 - 别用
net/http原生重试,用github.com/hashicorp/go-retryablehttp或自己封装带 context 取消的重试逻辑
服务发现与健康检查不能只靠 DNS
DNS 缓存、TTL 延迟、无健康感知,会让客户端持续往已宕机的实例发请求。Kubernetes Service 的 ClusterIP 在跨集群或混合云场景下也不够用。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用 Consul 或 Nacos 做服务注册中心,客户端集成
consul-api或nacos-sdk-go,主动拉取 + 长轮询监听变更 - 每个服务暴露
/health端点,返回 JSON 格式状态,字段包含status("up"/"down")、checks(DB 连接、依赖服务 ping 结果) - 服务发现客户端必须支持「剔除不健康实例」+「本地缓存兜底」,避免注册中心短暂不可用导致全链路雪崩
gRPC 连接复用与连接池要手动管
很多人以为 gRPC ClientConn 是线程安全且自动复用的,结果在高并发下每秒新建数百个 grpc.Dial,耗尽文件描述符、触发 connection refused 错误。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 全局复用一个
*grpc.ClientConn,用sync.Once初始化,别在 handler 里反复grpc.Dial - 如果必须多 endpoint(比如调不同环境的下游),按 endpoint 分 key 缓存
*grpc.ClientConn,并设置WithBlock()+WithTimeout()防止初始化卡死 - 启用 keepalive:
KeepaliveParams(keepalive.ClientParameters{Time: 30 * time.Second}),避免 NAT 超时断连后首请求失败
熔断器不是加个库就完事
用 sony/gobreaker 或 afex/hystrix-go 但没调参数,基本等于没开。默认阈值在真实流量下要么狂跳闸,要么完全不触发。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 按接口粒度配置熔断器,比如
paymentService.Process和userCache.GetByID分开管理 -
ReadyToTrip函数里统计最近 100 次调用:错误率 > 60% 且总请求数 ≥ 20 才熔断;恢复超时设为 60s,避免反复震荡 - 熔断开启后,必须返回明确错误(如
errors.New("circuit open")),让上游能区分是下游故障还是自身逻辑错
真正难的不是选组件,而是把超时、重试、熔断、健康检查这四层策略串成闭环 —— 每一层的输出,都得是下一层的输入依据。漏掉任意一环,冗余设计就变成假高可用。










