http/2多路复用是根本不同于keep-alive的连接模型,它在单tcp连接上并行处理多个请求流,不依赖空闲连接复用;需确保协议协商成功、tls启用、代理支持alpn,并转向流级而非连接级调优。

HTTP/2 的多路复用不是 keep-alive 的“升级版”,而是根本不同的连接模型——它不依赖“复用空闲连接”,而是在单个 TCP 连接上并行处理多个请求流。想用它替代传统 keep-alive 调优,关键不是配置更多参数,而是确保协议协商成功、连接真正走 HTTP/2,并让客户端和服务端都按流式逻辑工作。
确认 HTTP/2 协议已实际启用
Keep-alive 是 HTTP/1.1 的优化补丁,而 HTTP/2 多路复用必须双方明确协商。常见失败点:
- 客户端未显式要求 HTTP/2(如 Go 的
http.Client默认支持,但若服务端不支持或 TLS 握手失败,会自动降级到 HTTP/1.1) - 服务端未启用 TLS(HTTP/2 在浏览器中强制要求 HTTPS;Go 的
http.Server需搭配tls.Config才能协商 HTTP/2) - 中间代理(如 Nginx)未开启
http2并正确透传,例如 Nginx 配置中漏掉listen 443 ssl http2; - 使用了不支持 ALPN 协商的旧版 OpenSSL 或 Go runtime(建议 Go ≥ 1.8,OpenSSL ≥ 1.0.2)
关闭对 keep-alive 参数的过度依赖
HTTP/2 下,MaxIdleConns、IdleConnTimeout 等 Transport 参数作用大幅减弱。因为:
- 连接不再靠“空闲等待复用”,而是长期保持活跃并承载多个并发流
-
MaxIdleConnsPerHost不再决定并发能力,真正限制并发的是MaxConcurrentStreams(服务端设置)和客户端流配额 - 不必再担心
resp.Body.Close()忘记调用导致连接卡死——HTTP/2 流可独立关闭,不影响其他流
建议:Transport 中保留合理值(如 IdleConnTimeout: 90 * time.Second),但无需为压测反复调参;重点转向流级控制。
按流(stream)而非连接设计客户端行为
HTTP/2 的并发本质是流并发,不是连接并发。这意味着:
- 一个
http.Client实例 + 一个 TCP 连接,就能同时发 100 个请求(只要服务端允许足够多的并发流) - 不需要为高并发预热大量 idle 连接,也不用计算“每个 host 开多少连接”
- 错误处理要细化到流粒度:某个流因超时或 RST_STREAM 失败,不影响其他流继续传输
- 优先级(Priority)可主动设置,比如把 API 元数据请求设为高优先级,大文件下载设为低优先级
服务端需适配流式生命周期管理
服务端不能沿用 HTTP/1.1 的连接池思维。关键调整:
- Go 的
http.Server默认启用 HTTP/2,但需检查MaxConcurrentStreams(默认 100),必要时提高(如250) - 避免在 handler 中做阻塞操作,否则会占用整个连接上的多个流资源
- 禁用或谨慎使用
ReadTimeout/WriteTimeout,它们作用于整个连接;改用 per-stream 上下文控制(如ctx.WithTimeout) - 若前端有反向代理(如 Nginx),确保其
http2_max_concurrent_streams与后端一致,避免中间截断










