go默认maxidleconnsperhost=2是保守设计,旨在避免服务端不兼容导致的连接异常;高并发时易引发超时、time_wait堆积及端口耗尽,需据qps、协议类型协同调大maxidleconns、maxidleconnsperhost与idleconntimeout,并确保服务端支持keep-alive。

默认值 2 是保守设计,不是性能最优解,而是为了防止客户端在未知服务端行为时过度占用资源。
为什么 Go 官方把 MaxIdleConnsPerHost 设为 2
这个值不是凭空定的,它反映的是 Go 团队对「通用 HTTP 客户端」的默认假设:
- 多数服务端(尤其老旧或配置简陋的)不支持或不友好地处理大量 Keep-Alive 连接,过高的复用连接可能被对方主动 RST 或超时断开
- 客户端侧若盲目维持大量空闲连接,会快速耗尽文件描述符(
too many open files),尤其在访问大量不同 host 的场景下 - 2 是一个足够低的数,能避免绝大多数服务端不适配问题,同时保留基础复用能力——至少比每次都新建连接强
MaxIdleConnsPerHost = 2 在真实压测中会出什么问题
现象非常典型,且容易误判为网络或服务端故障:
-
net/http: request canceled (Client.Timeout exceeded while awaiting headers):连接池只有 2 个空闲连接,第 3 个请求就得等,等不及就超时 - 大量
TIME_WAITsocket 堆积:连接刚用完就被关,无法复用,频繁建连断连 -
dial tcp: can't assign requested address:本地 ephemeral 端口被快速耗尽(Linux 默认约 32K),根本原因是连接没复用上 - QPS 上不去但 CPU/内存不高:瓶颈卡在连接建立阶段,而非业务逻辑
怎么设才合理:看协议、看目标、看并发
没有万能值,但有可落地的判断依据:
- HTTP/1.1 场景(如调支付网关、内部 RPC):
MaxIdleConnsPerHost至少设为预期峰值 QPS 的 1/3~1/2;60 QPS → 设 20~30 - HTTP/2 场景(单连接多路复用):
MaxIdleConnsPerHost可设更高(如 1000),因为单连接承载能力强,但要注意MaxIdleConns必须 ≥ 它 - 必须同步调大
MaxIdleConns:如果只改MaxIdleConnsPerHost而MaxIdleConns仍是默认 100,那最多只能分给 5 个 host(100 ÷ 20),其余 host 就拿不到空闲连接 - 别忘了
IdleConnTimeout:设太长(如 90s)会导致空闲连接长期占着 fd 却无实际用途;建议 30s 左右,兼顾复用与释放
最容易被忽略的一点
MaxIdleConnsPerHost 是客户端单方面“愿意保留”的数量,它不保证服务端真会 Keep-Alive。如果响应头里没有 Connection: keep-alive 或服务端主动关闭连接,再大的值也白设。上线前务必用 curl -v 或 Wireshark 确认服务端是否真的返回了 keep-alive 响应。











