HTTP/2 多路复用对压测结果的影响是什么,如何确认服务器真正开启了 h2

解读

国内互联网公司的性能测试面试里,这道题同时考察“协议理解深度”与“可落地的验证手段”。
面试官想听的不只是“并发变高”,而是:

  1. 多路复用如何改变了并发模型、RT 分布和资源消耗曲线;
  2. 压测工具如果不升级模型,会把 h2 的优势测成“假瓶颈”;
  3. 线上灰度或容器集群里,如何排除“中间层协商失败”导致的 h1.1 回退。
    回答必须结合国内常用链路(阿里云 SLB + Nginx + Ingress + Envoy)给出量化差异和排查命令,否则会被认为“只背了概念”。

知识点

  1. HTTP/2 帧层多路复用:单 TCP 连接内逻辑流(Stream)并行,队头阻塞从“请求级”降到“帧级”。
  2. 并发模型变化:h1.1 时代“并发度≈连接数”,h2 时代“并发度≈Stream 数”,连接数不再是瓶颈。
  3. 压测指标漂移:
    • 同等虚拟用户数下,h2 场景连接数下降 1–2 个数量级,TCP 握手、TIME_WAIT 减少,但单连接窗口与流控竞争可能导致 RT 长尾增加。
    • 吞吐量曲线更早出现“斜率变缓”——不是服务器 CPU 到顶,而是单连接流控或内核 TCP 写缓冲打满。
  4. 工具陷阱:
    • JMeter 5.x 默认仍按“连接池”模型发压,若未勾选“HTTP2 Sampler”,会把 200 条 Stream 压成 200 条连接,结果比 h1.1 还差。
    • locust、wrk2 需要额外插件或编译选项才能启用 h2,否则直接回落 h1.1。
  5. 国内链路验证点:
    • 四层 LB(SLB、CLB)仅透传 ALPN,不终结 h2;七层 LB(ALB、Tengine-Ingress)默认只对外 h2,对内仍 h1.1,需确认“后端协议”字段。
    • Nginx 需要 listen 443 ssl http2 同时保证 openssl ≥1.0.2;容器 sidecar(Envoy、MOSN)要在 listener filter 显式开启 alpn_h2。
  6. 确认手段:
    • 应用层:curl -v --http2 -H 'Accept-Encoding: gzip' https://domain 出现 “Using HTTP/2” 且响应头里无 Connection: close。
    • 传输层:tshark -Y 'tls.handshake.extension.type == 16' -T fields -e tls.handshake.extensions_alpn_str 看到 h2。
    • 压测层:JMeter 的 View Results Tree 取样器里,取样头字段 HTTP-Sampler-Protocol=HTTP/2;或者 gRPC 场景直接看 netty 日志 InitialSettingsHandler 收到 SETTINGS 帧。
    • 系统层:ss -ntp | grep :443 观察单连接上持续上涨的 send-q 且连接数不随并发线性增加。

答案

HTTP/2 多路复用把“并发度”从连接维度搬到帧维度,对压测结果带来三点核心影响:

  1. 连接数骤降,同等并发用户下 TIME_WAIT 减少 90% 以上,内核 CPU 消耗下降,但单连接内存占用上升;
  2. RT 分布出现“长尾增厚”现象,因为单连接流控、头部压缩动态表竞争及内核 TCP 写缓冲打满,导致 95/99 分位可能比 h1.1 高 10–30%;
  3. 吞吐量拐点提前,容易被误判为“服务器瓶颈”,实则是单连接窗口或 HTTP/2 SETTINGS 初始值限制,调大 SETTINGS_INITIAL_WINDOW_SIZE 或开启多连接聚合后 TPS 可继续提升。

确认服务器真正开启 h2 的“国内实用四步法”:

  1. 客户端快速验证:curl -v --http2 https://域名 2>&1 | grep 'Using HTTP/2',出现即表示 ALPN 协商成功;
  2. 抓包看 ALPN:tshark -i eth0 -f 'tcp port 443' -Y 'tls.handshake.type==1' -T fields -e tls.handshake.extensions_alpn_str,结果包含 h2;
  3. 压测工具自检:JMeter 5.5 勾选 HTTP2 Sampler,结果树里查看取样头协议为 HTTP/2,且单连接并发 100 条请求只建 1 条 TCP;
  4. 线上灰度对比:在同一 ECS 压测机分别指定 --alpn-h2 与 --alpn-http/1.1 跑 wrk,观察 ss -s 输出 TCP 连接数差异,若 h2 场景连接数恒定而 h1.1 随并发线性增长,即可证明链路未回退。

拓展思考

  1. 多路复用并非“免费午餐”:在移动端弱网或高丢包链路下,单连接队头阻塞虽减轻,但一旦出现 TCP 重传,所有逻辑流一起受损;国内 4G/5G 网络模拟显示,丢包率 1% 时 h2 整体耗时反而比并发 h1.1 高 15%。
  2. 压测模型要升级:传统“线程=虚拟用户”模型已失效,建议采用“异步协程+流复用”模式,如基于 k6 experimental/http 或 Gatling 3.9 http2 协议层,才能准确压出服务器真实极限。
  3. 后端语言差异:Go 默认 net/http 对 h2 的 SETTINGS_MAX_CONCURRENT_STREAMS 初始值 250,Java Netty 默认 100,若压测并发高于该值未做流控等待,会收到 RST_STREAM,表现为成功率骤降 1–2%。
  4. 监控联动:在 Prometheus 里同时记录 nginx_connections_active 与 ingress_http2_requests_total,可一眼看出“连接数平稳但 h2 请求上涨”,从而快速区分“带宽瓶颈”与“单连接流控瓶颈”。