HTTP/2 消除 HTTP 响应顺序阻塞
这里的“消除队头阻塞”,指解除同一条连接上的 HTTP 响应顺序约束,而不是消除 TCP 队头阻塞。较晚发起的响应可以在较早的处理函数仍然等待时完成,但共享的传输容量、连接级流控和应用瓶颈,依然可能把不同流的进度关联起来。先说明这一层边界,才能区分应用协议的顺序约束与底层传输等待。 分清两种排队 HTTP/1.1 本来就支持持久连接,并非一个请求必须新建一条连接。多个请求可以顺序复用套接字;流水线还允许同时存在多个未完成请求,服务器也可以并行处理安全方法,但同一条连接上的响应必须按照请求顺序发送。因此,第一份响应过慢,会延迟后续响应的交付。客户端经常通过多开连接缓解这个限制。 HTTP/2 给帧关联流标识,在同一条连接上交错传递消息。服务器可以发送已经准备好的响应,不必先完成另一份无关响应。这是 HTTP 层的独立推进能力,不代表每个处理函数获得独占处理器、数据库、带宽或无限调度机会,也不意味着应用的共享资源自动变成互不影响。 TCP 仍然提供一个有序字节流。某段字节缺失时,后面已收到的字节可能必须等待补齐,才能交付应用,其中也可能包含其他 HTTP/2 流的帧;此前已交付字节不会被收回。HTTP/3 使用 QUIC,每条流内仍保持有序,但没有跨流的统一传输交付顺序。共享拥塞与流控预算、应用依赖和 QPACK 头部依赖仍可能产生等待。这是另一协议的规范背景,不是本例执行了 HTTP/3 实验。 并发仍然受到预算约束 对端通过 SETTINGS_MAX_CONCURRENT_STREAMS 限制本方向向它发起的流。非空 DATA 载荷同时消耗流级和连接级额度,计入填充,不计帧头。连接额度耗尽可能阻塞其他流的 DATA;但携带 END_STREAM 的空 DATA 帧仍可在零额度时发送,控制帧不消耗这些窗口。接收方消费正文、更新窗口,以及共享工作池、锁和上游连接的情况,仍会影响实际进度。 应检查所测那一跳真正协商出的协议。浏览器到代理使用 HTTP/2,不能证明代理到源站也是如此;TLS 握手成功也不足以证明使用了 HTTP/2。Go 配置自定义 TLS 参数后,可能需要 ForceAttemptHTTP2 才会尝试 HTTP/2,但最终证据仍是响应协议和协商出的 h2,而不是配置字段已经存在。 ...