3.5 KiB
3.5 KiB
native HTTP/2 进入条件
当前 transport/native 是经过 Linux 长连接和反向代理验收的 HTTP/1.1 实现。HTTP/2 暂不直接打开,原因是它把一个 TCP 连接变成多个独立请求流,连接级的 Keep-Alive、超时和并发限制不能直接复用现有 HTTP/1.1 状态机。
当前已提供独立的 transport/http2 实验 Runner。它已经验证 TLS/h2、h2c、本地连接和请求闸门、GOAWAY 排空以及 RST_STREAM 取消;这些结果用于验证生命周期设计,不代表 native 已经启用 HTTP/2。
目标边界
- HTTP/2 必须作为显式 opt-in 协议,不改变
omni.New()、transport/nethttp或 native HTTP/1.1 的默认行为。 - TLS ALPN 只在 HTTP/2 实现通过全部验收后增加
h2;当前 native 只宣告http/1.1,误配h2会在启动时失败。 - Handler、Service、统一响应、requestId、可信代理和业务日志继续复用现有
httpx.Context与http.Handler边界。 - h2c 只用于本地测试,生产入口使用 TLS + ALPN;不能把明文升级路径默认为公网协议。
连接和流的生命周期
- accept loop 先执行连接上限检查,再执行 TLS 握手;握手受独立超时约束,不能占满连接槽位后无限等待。
- TLS 协商得到
h2后进入 HTTP/2 connection state;其他 ALPN 直接关闭,不能把 HTTP/2 preface 交给 HTTP/1.1 解析器。 - 每个 stream 创建独立的
http.Request和取消 context。RST_STREAM只取消当前请求,TCP 断开才取消该连接上的所有请求。 MaxConcurrentRequests是所有连接共享的全局请求闸门;MaxConcurrentStreams限制单连接并发流;两者都必须在收到完整请求体前生效。- 服务关闭时停止 accept,发送 GOAWAY 拒绝新流,等待活动流排空;超过
ShutdownTimeout后关闭连接并取消剩余请求。实验 Runner 已覆盖这条顺序。
必须可观测的状态
HTTP/2 版本需要在 native Stats 之外至少记录:活动 stream、被拒绝 stream、连接级 protocol error、RST_STREAM、GOAWAY 发送次数,以及因流控或并发闸门触发的拒绝。计数必须是原子快照,不能在 metrics handler 中锁住连接状态机。
进入实现前的验收矩阵
- TLS ALPN:只协商
h2,HTTP/1.1 客户端仍由现有 native 路径处理;不支持的 ALPN 在握手前后都不会误入错误解析器。 - 多路复用:一个连接并发至少 128 个 stream,响应和 requestId 不串线,单个慢 stream 不阻塞其他 stream。
- 流控:慢读取、慢写、窗口耗尽和大 body 都能恢复;内存不会随未消费 body 无限增长。
- 取消:RST_STREAM、客户端断开、服务关闭分别只影响应受影响的请求,并能在 metrics 中看到回收;当前实验 Runner 已覆盖 RST_STREAM 与服务关闭。
- 背压:连接上限、全局 stream 上限、单连接 stream 上限和 header/body 上限均能快速拒绝并自动恢复。
- 代理联调:Nginx/Cloudflare 的 TLS、Keep-Alive、超时、GOAWAY 和优雅发布行为与 HTTP/1.1 回源结果一致。
- 长测:Linux amd64 至少 30 分钟 TLS、多连接、多 stream、慢客户端混合场景;要求 0 协议错误、0 请求串线,连接、stream、goroutine 和 FD 在停止后回收。
只有上述矩阵完成,才把 h2 加入 native 的 TLS ALPN,并考虑把 HTTP/2 作为独立版本能力发布。此前生产环境使用 Nginx/Cloudflare 终止 HTTP/2 后以 HTTP/1.1 回源,或使用支持 HTTP/2 的 transport/nethttp。