跳到内容

11.2 HTTP/3、QPACK、发现与部署

旧连接在丢包时会拖住同车的请求,信标塔准备试用 HTTP/3,但上线前必须弄清发现、回退和观测方式。

HTTP/3 保留 HTTP method、status、field 和 caching semantics,将 framing/multiplexing 映射到 QUIC。它不是一套新 REST semantics,也不是“任意 HTTP/2 frame 原样搬到 UDP”。

1. HTTP/1.1、HTTP/2 与 HTTP/3 的分层

text
HTTP/1.1: semantics -> HTTP/1.1 textual framing -> TCP -> IP
HTTP/2:   semantics -> HTTP/2 binary frames    -> TCP -> IP
HTTP/3:   semantics -> HTTP/3 frames           -> QUIC -> UDP -> IP

HTTP/1.1 可在一条 persistent connection 上处理多个 request,pipelining 也允许先发多 request,只是 response 必须按顺序返回且 ecosystem support 有限。因此“HTTP/1.1 一个 connection 一次只能有一 request”是常见 deployment simplification,不是 wire protocol 唯一能力。

HTTP/2 在同一 TCP connection 上 multiplex HTTP stream,解决 HTTP/1.x response ordering/application framing HOL,但遇到 TCP byte gap 时多条 stream 都要等 kernel 补齐。HTTP/3 借 QUIC stream 减少这个 cross-stream transport HOL。

HTTP/3 不是必然更快。Low-loss low-RTT path、warm TCP/TLS connection、UDP throttling、QUIC CPU/crypto implementation、server scheduling 和 application dependency 都可决定 result。应以 target network/user workload 实测,而不用 protocol name 代替 measurement。

2. HTTP/3 stream type

HTTP request/response 使用 client-initiated bidirectional QUIC stream。Typical sequence:

text
request stream:
  HEADERS -> optional DATA -> optional trailers(HEADERS)
  response HEADERS -> optional DATA -> optional trailers(HEADERS)

HTTP/3 frame 不与 QUIC packet boundary 对齐。一个 H3 frame 可跨多个 STREAM frame/QUIC packet,一个 QUIC packet 也可携带多条 stream 的 data。

Critical unidirectional streams:

  • 每个 endpoint 的 HTTP/3 control stream,携带 SETTINGS、GOAWAY、MAX_PUSH_ID 等;
  • QPACK encoder stream;
  • QPACK decoder stream。

Critical stream 被关闭是 connection error。Unknown unidirectional stream type 通常要忽略/consume,以允许 extension;不能把所有 unknown type 都当 attack 立即断连,也要用 resource limit 防止 peer 无限开 unknown stream。

3. QPACK 为 QUIC out-of-order stream delivery 设计

HPACK 借 HTTP/2/TCP 的全局 ordered byte delivery 同步 dynamic table update。如果直接将同样 dependency 放到多条独立 QUIC stream,request stream 的 compressed field section 可比 dynamic-table insertion 先到。

QPACK 的两个 endpoint 各自维护 encoder/decoder state 和对端 table view:

  • Encoder stream 从 encoder 发 table insertion/duplication/capacity instruction 给 peer decoder;
  • Decoder stream 从 decoder 发 section acknowledgment、stream cancellation 和 insert-count increment 给 peer encoder;
  • Request stream 上的 field section 携带 Required Insert Count/Base 等 information,表明解码 dependency。

Decoder 如果还没收到必需 insertion,可阻塞该 request stream 的 header decoding。SETTINGS_QPACK_BLOCKED_STREAMS 限制 peer 允许的 blocked-stream 数,encoder 可选 static/literal 表示避免超限。所以 QPACK 是将 compression efficiency 与 HOL risk 变成可控 trade-off,不是完全消除 blocking。

Dynamic table 在每个 direction 的 encoder/decoder pair 中同步,不宜简化成“服务器一张 encoder table、客户端一张毫无关系的 decoder table”。Decoder 必须按 encoder instruction 构建一致 dynamic entries,只是 request stream 不必按全局顺序到达。

4. Discovery:Alt-Svc 是 HTTP field,HTTPS RR 才是 DNS

Origin 可在 HTTP/1.1/2 response 中用 Alt-Svc 宣告 HTTP/3 alternative service:

http
Alt-Svc: h3=":443"; ma=86400

Alt-Svc 是 HTTP response field,不能用 dig 查“Alt-Svc DNS record”。Client 可缓存 alternative service,后续尝试 QUIC;certificate 仍要对 origin identity 有效,不是 Alt-Svc host 说什么就信什么。

DNS SVCB/HTTPS resource record(RFC 9460)也可宣告 service binding、ALPN(如 h3)、port/address hint 等:

bash
dig example.com HTTPS

Address hint 是 hint,client 还要按 record/normal A/AAAA resolution 和 connection policy 处理,不能将 hint 当作 authoritative replacement address。DNSSEC 与 encrypted DNS 的边界也与 7.1 相同。

5. Fallback 要避免 UDP black hole 拖慢 page load

Enterprise network、firewall、NAT、QoS/policer 可阻断或降速 UDP/443。HTTP client 不应把 QUIC 当唯一 path,除非 application contract 本来就只支持 QUIC。Browser 常根据 cached Alt-Svc/HTTPS RR 和 past network behavior 决定 racing/fallback,但 exact timeout 和算法是 implementation policy。

“QUIC 失败后再等很久才串行连 TCP”会引入 protocol fallback penalty。Happy-Eyeballs-style racing、brokenness cache 和 connection reuse 可降低惩罚,但也增加 duplicate handshake/load。要观测 attempted protocol、fallback reason/time 和 final negotiated protocol,不只看最终 response 成功。

6. Load balancer 要能根据 CID 稳定路由

QUIC packet 的 source address 可因 NAT rebinding/migration 变化,只按 five-tuple 将 UDP datagram 分到 backend 会破坏 connection continuity。Common deployment:

  • Edge/load balancer 终止 QUIC;
  • Load balancer 从 server-issued CID 中解码/rendezvous-hash backend ID,将 packet 转给持有 connection state 的 server;
  • Shared/external connection-state store(高成本);
  • Stateless reset key 管理,让无 state endpoint 可通知 peer connection 不存在。

CID encoding 会暴露 routing metadata/linkability,需要 encryption/rotation/versioning 和 key lifecycle。QUIC-LB 之类规范给出 load-balanced CID 的通用设计,但 deployment 仍要解决 backend draining、CID issuance/retirement、stateless reset 与 key rotation。

7. 0-RTT 在 HTTP 层的处理

HTTP Early Data 用 Early-Data: 1 将 early request 信息向 upstream 传递,intermediary/origin 如果无法安全处理可返 425 Too Early。Client 收到 425 后应在 handshake 完成后重试,而不是再用 early data 循环重试。

Policy 不应只看 method name:

  • GET 可触发 logging、billing、one-time link 或 non-compliant side effect;
  • PUT 在 HTTP semantics 中 idempotent,但 repeated processing 仍可增加 audit/notification cost;
  • Authentication credential 可在 early data 中被 replay to same service context;
  • Distributed anti-replay cache 的 consistency/availability 有 trade-off,不存在不付成本的 absolute replay prevention。

对重要 state-changing request,最稳妥默认是等 1-RTT。确实需要 early data 时,设计 application idempotency key、replay window、credential scope 和 duplicate response semantics。

8. 运行时观测与 packet capture

bash
# 先确认 curl build 是否支持 HTTP/3
curl --version

# 允许 client 选 HTTP/3,具体 behavior 查当前 curl 文档
curl -v --http3 https://example.com/

# 只尝试 HTTP/3,用于区分 QUIC path 是否可用
curl -v --http3-only https://example.com/

# QUIC 通常使用 UDP/443,但不是 protocol 硬编码只能 443
tcpdump -ni any udp port 443

System curl 可能没编译 HTTP/3 backend,此时 option 不可用,不代表 server 不支持。Test 要记录 curl/backend version,不强制用某个公网测试站作永久依赖。

QUIC payload/header 大部分 encrypted,passive capture 不像 TCP 那样直接看 HTTP fields。可观测性要结合:

  • Application access log/trace;
  • QUIC transport metrics:handshake outcome、0-RTT accepted/rejected、PTO/loss、RTT、cwnd/pacing、flow-control blocked、migration/path validation;
  • qlog(implementation support);
  • TLS key log + Wireshark(只在授权调试环境安全保管 secret);
  • Optional spin bit/passive signal,受 privacy/configuration 影响,不能假设始终存在。

9. Capacity 与 DoS boundary

QUIC/TLS handshake 可在 UDP 上对 server 产生 CPU/state cost。Deployment 需要:

  • Address-validation/Retry policy;
  • Per-IP/prefix/global handshake rate limit;
  • 3x amplification compliance;
  • Connection/stream/buffer/QPACK table limit;
  • Stateless reset token/key protection;
  • TLS certificate chain 大小与 handshake fragmentation;
  • UDP receive buffer、batching/GRO/GSO 和 worker affinity;
  • TCP HTTP/2 fallback capacity,不能因 HTTP/3 launch 就缩没。

Firewall 只“开 UDP/443”不等于部署完成:NAT timeout、load-balancer CID routing、fragment/MTU、QoS、DDoS protection 和 observability 都要经过 pressure/failure test。

10. 验收问题

  1. HTTP/3 frame、QUIC STREAM frame 和 QUIC packet boundary 为什么不同?
  2. QPACK 为什么仍可 blocked,SETTINGS_QPACK_BLOCKED_STREAMS 解决什么?
  3. Alt-Svc 与 DNS HTTPS RR 分别从哪个 protocol 获得?
  4. QUIC load balancer 为什么不应只按 five-tuple 选 backend?
  5. curl --http3-only 失败能证明什么,还需要记录哪些 client/environment evidence?
  6. HTTP 425 应如何重试,为什么不能再用 early data?

参考

Built with VitePress | Software Systems Atlas