必须自定义 http.Client 并设置超时(≤5s)、连接池参数,禁用 http.Get/Post 简写;Consul/etcd 客户端需配置重试与短超时;日志须集成 traceID 且结构化输出;服务注册必须配真实健康检查与 TTL 自动续期。

http.Client 不设超时,线上必挂
Go 的 http.DefaultClient 没有默认超时,压测或网络抖动时立刻出现 net/http: request canceled (Client.Timeout exceeded)。这不是偶发错误,是必然结果。
- 必须自定义
http.Client,显式设置Timeout(建议 ≤ 5s)、Transport中的MaxIdleConns和MaxIdleConnsPerHost(例如都设为 100) - 禁用
http.Get/http.Post简写——它们底层全走DefaultClient,连接复用和超时完全失控 - 下游返回 404 时别直接 panic:可能是服务未上线、路径写错,或注册中心还没同步,需区分处理
Consul/etcd 客户端连不上,不是配置错,是重连逻辑没写
Consul 官方 client 默认不重试、不自动重连;etcd 的 WithRequireLeader 在 leader 切换时会卡住整个 Get 调用,不是“连不上”,是“卡死”。
- Consul:用
consul.NewClient时必须传入自定义config.HttpClient,该 client 需带重试(如retryablehttp)和短超时(≤ 2s) - etcd:
WithRequireLeader禁用,改用WithSerializable;watch 必须用带 cancel 的context.Context,否则 goroutine 泄漏 - 本地开发别直连生产集群:用
consul agent -dev或etcd --enable-v2启单点,避免被远程配置拖慢调试
日志没 traceID,查故障等于盲人摸象
用 log.Printf 打日志,上下游请求链路断开,grep 十分钟不如重启服务。靠手动往 context.WithValue 塞 traceID 极易漏传、类型错、污染业务逻辑。
- 必须用结构化日志库(如
zap),输出 JSON 格式,字段含trace_id、service、span_id - HTTP 入口统一从 header 提取
X-Trace-ID(若无则生成),注入到 context 并透传给下游调用 - gRPC 用
grpc_zap中间件,HTTP 用 Gin/Echo 的 zap logger 中间件,避免手写日志拦截器
服务注册后不健康检查,等于把故障节点塞进负载均衡
只调 Register 不配健康检查,Consul/etcd 里服务一直显示 “passing”,但实例早已 panic 或卡死,流量照常打过去。
立即学习“go语言免费学习笔记(深入)”;
- HTTP 健康检查 endpoint 必须真实响应(不能 return 200 硬编码),且检查 DB 连接、缓存连通性等关键依赖
- Consul 用
Check.HTTP+Check.Timeout(建议 ≤ 1s);etcd 无原生健康检查,需自行实现 watch + 心跳上报 - 注册时设
TTL(如 30s),客户端定期 renew,断连后自动剔除,比被动探活更可靠


















