本页目录

协议演进与兼容

协议部署后就很难改了——TCP 固定 header 导致扩展花了十年,TLS 中间件对未知扩展的 buggy 行为导致 ossification。QUIC 从设计之初就内置版本协商和 GREASE(随机插入无意义扩展)对抗中间件僵化——这是所有新协议的必修课。

概述

协议不是一成不变的——部署后就很难改了。HTTP/1.1 headers 的文本灵活性使其可以无痛添加新特性(Cache-Control, CORS),但 TCP 的固定 header 导致扩展困难(TCP Fast Open 花了 10 年才普及)。QUIC 从设计之初就内置了版本协商和 GREASE(随机插入无意义扩展)——对抗中间件对未知字段的 buggy 行为造成的 protocol ossification。所有新设计的协议都应该实现 GREASE 和明确的扩展点。

Forward vs Backward

Forward compatible (新 client, 旧 server):
  未知字段: skip (protobuf, TLV)
  未知 frame type: ignore (HTTP/2)
  → 实现: "be liberal in what you accept"

Backward compatible (旧 client, 新 server):
  默认值填充
  版本号协商
  capability 位图 (TLS cipher suites)

协商与 Fallback

协商与 Fallback:三种机制,谁能改当前连接、谁只能改下一次

HTTP Upgrade GET / HTTP/1.1 + Upgrade: h2c 101 Switching 或 ignored

TLS ALPN ClientHello ALPN=[h2, http/1.1] ServerHello ALPN="h2"

HTTP Alt-Svc Alt-Svc: h3=":443" 下一次连接用 HTTP/3 (不升级当前连接)

HTTP Upgrade、TLS ALPN 都是同一连接内的实时协商;Alt-Svc 只是"下次换协议"的提示—— 不会升级当前连接,这正是"协商"与"fallback"的区别。

GREASE

问题: 中间件 (防火墙, NAT) 只认识它知道的 byte pattern
  → 新 protocol extension → 被丢弃 (不认识) → protocol 无法演进

GREASE: 客户端随机插入无意义的 extensions/values:
  TLS: random cipher suites in ClientHello
  HTTP/2: random SETTINGS parameters
  QUIC: random transport parameters

目的: 中间件必须正确处理 unknown values (ignore, not reject)
  → 未来真正的 extension 不会被中间件阻塞

QUIC 的教训

QUIC 的教训:TCP 的四个老问题,逐个逆向设计 ① Header 明文 → middlebox 修改 → ossification QUIC:flags 全加密 middlebox 只见 Connection ID ② 无版本协商 → 演进缓慢 QUIC:version 在首包 服务器可拒绝并提议其他 version ③ 5-tuple 绑定 → NAT rebinding → disconnect QUIC:Connection ID 与 IP / port 无关 ④ Extension detection QUIC:GREASE 内置 于每个 QUIC 实现 四类教训的共同逻辑:把明文、无协商、地址绑定、扩展检测这些让 TCP 僵化的设计, 在 QUIC 里逐一反过来做——这是"协议演进"这门课的必修内容。

参考

  • GREASE: RFC 8701
  • QUIC Appendix A: RFC 9000 (design rationale)

Keywords: forward compatibility, backward compatibility, GREASE, ossification, QUIC, Alt-Svc