线上调用 OpenAI API 一旦出现超时,最烦的不是“偶发失败”,而是你不知道到底卡在 DNS、TLS、代理,还是你自己的连接池。
这篇给你一套可直接落地的排查顺序:先判定超时发生在哪一段,再用指标和最小实验定位,最后给可复制的 Go 配置模板,避免同类事故反复出现。
一、先把“超时”拆成 4 段,不要一锅炖
在 Go 的 HTTP 调用链里,OpenAI 请求通常会经过:
- DNS 解析
- TCP 建连 + TLS 握手
- 代理转发(如果你走公司出口或自建网关)
- 请求发送与响应读取(含流式返回)
只看 context deadline exceeded 没意义。你必须知道“超时发生在哪一段”。
二、最小可观测配置:把链路耗时打出来
先上一个可观测的 http.Transport 模板:
package main
import (
"context"
"crypto/tls"
"log"
"net"
"net/http"
"net/http/httptrace"
"time"
)
func newClient() *http.Client {
dialer := &net.Dialer{Timeout: 3 * time.Second, KeepAlive: 30 * time.Second}
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: dialer.DialContext,
TLSHandshakeTimeout: 5 * time.Second,
ResponseHeaderTimeout: 30 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
IdleConnTimeout: 90 * time.Second,
MaxIdleConns: 200,
MaxIdleConnsPerHost: 50,
MaxConnsPerHost: 100,
TLSClientConfig: &tls.Config{MinVersion: tls.VersionTLS12},
ForceAttemptHTTP2: true,
}
return &http.Client{Transport: tr, Timeout: 45 * time.Second}
}
func withTrace(req *http.Request) *http.Request {
trace := &httptrace.ClientTrace{
DNSStart: func(i httptrace.DNSStartInfo) { log.Printf("dns_start host=%s", i.Host) },
DNSDone: func(i httptrace.DNSDoneInfo) { log.Printf("dns_done addrs=%v err=%v", i.Addrs, i.Err) },
ConnectStart: func(network, addr string) { log.Printf("connect_start %s %s", network, addr) },
ConnectDone: func(network, addr string, err error) { log.Printf("connect_done %s %s err=%v", network, addr, err) },
TLSHandshakeStart: func() { log.Printf("tls_start") },
TLSHandshakeDone: func(state tls.ConnectionState, err error) { log.Printf("tls_done vers=%x cipher=%x err=%v", state.Version, state.CipherSuite, err) },
GotConn: func(info httptrace.GotConnInfo) { log.Printf("got_conn reused=%v was_idle=%v idle=%s", info.Reused, info.WasIdle, info.IdleTime) },
}
return req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
}
func main() { _ = withTrace }
三、按优先级排查(实战顺序)
1) DNS 超时
典型症状:lookup api.openai.com: i/o timeout。
dig api.openai.com
nslookup api.openai.com
处理:稳定 DNS、容器显式 dnsConfig、复用 client 减少重复解析。
2) TLS 握手超时
典型症状:net/http: TLS handshake timeout。
openssl s_client -connect api.openai.com:443 -servername api.openai.com -brief
curl -v --connect-timeout 5 https://api.openai.com/v1/models
处理:检查代理证书链和系统时间,别无脑把超时调到 60s。
3) 代理链路抖动
处理:对比直连与代理成功率,给代理做健康检查,幂等请求才重试。
4) 连接池配置不当
处理:全局复用 http.Client,调大 MaxConnsPerHost,流式响应必须 close body。
四、保守参数建议
- Dial: 3s
- TLS: 5s
- ResponseHeader: 30s
- Client.Timeout: 45s
- MaxConnsPerHost: 100
- MaxIdleConnsPerHost: 50
五、总结
超时不是玄学。拆链路、看 trace、按段修,你会比“盲目重试”快得多。