3. HTTP/2 协议基础:二进制分帧、多路复用、流优先级、头部压缩 (HPACK)

HTTP/2 是 gRPC 的默认传输协议,其核心设计目标是通过解决 HTTP/1.x 的队头阻塞(Head-of-Line Blocking)和低效的头部传输问题,显著降低网络延迟。理解 HTTP/2 的四大核心机制——二进制分帧、多路复用、流优先级和头部压缩 (HPACK)——是诊断服务网格中 gRPC 延迟问题的前提。

3.1 二进制分帧层 (Binary Framing Layer)

HTTP/2 将 HTTP 语义(方法、路径、头部等)封装在二进制格式的帧(Frame)中,而非 HTTP/1.x 的文本格式。这是所有高级特性的基础。

  • 帧 (Frame):HTTP/2 中最小的通信单元,包含一个固定 9 字节的头部(Length, Type, Flags, Stream Identifier)和可变长度的负载(Payload)。
  • 消息 (Message):一个完整的 HTTP 请求或响应,由一组逻辑相关的帧组成(例如:HEADERS 帧 + DATA 帧)。
  • 流 (Stream):一个虚拟的、双向的、可复用的连接通道,用于在单个 TCP 连接上承载多个消息。每个流由唯一的整数标识符(Stream ID)标记。
延迟诊断要点: 二进制分帧使得协议解析更高效,但帧的组装顺序和流的状态管理直接影响延迟。在服务网格中,Envoy 或 Linkerd 代理需要解析这些帧以进行流量管理,帧处理不当(如乱序重组)会引入额外的代理延迟。
HTTP/2 二进制分帧与流结构 帧 (Frame) 结构 Length Type Flags Stream ID Payload (可变长度) 流 (Stream) 与消息 (Message) 关系 Stream 1 (请求) HEADERS 帧 (Method: GET) DATA 帧 (Body Part 1) DATA 帧 (Body Part 2) Stream 3 (响应) HEADERS 帧 (Status: 200) DATA 帧 (Response Body) Stream 5 (请求) HEADERS 帧 (Method: POST) DATA 帧 (gRPC Protobuf) 说明:多个流(Stream 1, 3, 5)的帧在同一个 TCP 连接上交错传输,实现多路复用。

3.2 多路复用 (Multiplexing)

HTTP/2 允许在单个 TCP 连接上同时打开多个流,每个流独立地发送请求和接收响应。帧在连接上交错传输,接收方根据 Stream ID 将帧重组为完整的消息。

特性 HTTP/1.x (无多路复用) HTTP/2 (多路复用)
连接数 通常 6-8 个并行 TCP 连接 单个 TCP 连接
队头阻塞 存在(请求必须排队等待响应) 基本消除(流级别独立)
资源开销 高(多个连接、TLS 握手) 低(连接复用)
延迟影响 高延迟,尤其在高 RTT 场景 低延迟,流间无阻塞
注意: 虽然 HTTP/2 消除了应用层的队头阻塞,但 TCP 层的队头阻塞仍然存在。如果 TCP 包丢失,所有流都会被阻塞,直到丢包重传完成。这是 gRPC 在弱网环境下延迟抖动的主要原因之一。

3.3 流优先级 (Stream Priority)

HTTP/2 允许客户端为每个流分配优先级,以告知服务器哪些请求更重要。优先级通过依赖树 (Dependency Tree) 和权重 (Weight) 实现。

  • 依赖 (Dependency):流可以依赖另一个流,表示前者应在后者之后处理。
  • 权重 (Weight):在同一个依赖层级中,权重值(1-256)决定了资源分配的比例。
  • 默认行为:如果未设置优先级,所有流默认依赖根流(Stream 0),权重相同。
延迟诊断要点: 在服务网格中,如果 sidecar 代理错误地处理或重置了流的优先级,可能导致关键请求(如健康检查、控制面信令)被非关键请求(如批量数据流)阻塞,从而引发延迟尖刺。Envoy 的 HTTP/2 编解码器配置(如 envoy.http_connection_manager)中的优先级策略需要仔细审查。

3.4 头部压缩 (HPACK)

HTTP/2 使用 HPACK 算法对头部进行压缩,大幅减少头部开销。HPACK 结合了静态表、动态表和Huffman 编码。

HPACK 组件 说明 延迟影响
静态表 预定义的 61 个常见头部字段(如 :method: GET、:status: 200) 零延迟,直接索引
动态表 动态维护的已发送头部缓存,后续请求可引用索引 首次发送有编码延迟,后续请求延迟极低
Huffman 编码 对字符串值进行压缩,减少字节数 轻微 CPU 开销,但显著减少传输时间

HPACK 的延迟特征在 gRPC 场景中尤为关键。gRPC 的头部通常包含 :path(服务名/方法名)、content-type、te 等字段。在服务网格中,sidecar 代理(如 Envoy)会解析并可能修改这些头部(例如添加 x-request-id、authority 等),这会破坏动态表的一致性,导致代理需要重新编码头部,增加额外的延迟。

HPACK 头部压缩与解压缩流程 发送端 (编码) 原始头部 (method: POST) 静态表索引 (索引 3) 动态表查找 (未命中则新增) Huffman 编码 (字符串压缩) 压缩后的头部帧 (二进制索引 + 编码) 接收端 (解码) 接收压缩帧 Huffman 解码 动态表更新 (同步状态) 静态表索引 (查找) 还原原始头部 (method: POST) 网络传输
延迟诊断要点: 在服务网格中,如果 sidecar 代理(如 Envoy)修改了头部(例如添加 x-envoy-expected-rq-timeout-ms),会导致动态表条目失效,代理必须重新编码整个头部块。这增加了代理的 CPU 开销和延迟。建议在网格配置中启用 envoy.http_connection_manager 的 http2_protocol_options 中的 hpack_table_size 调整,以优化动态表大小。

3.5 总结:HTTP/2 延迟特征矩阵

机制 主要延迟收益 潜在延迟风险 网格诊断关注点
二进制分帧 解析效率高,帧处理快 帧重组逻辑复杂,可能引入代理延迟 代理的帧缓冲区大小和重组超时
多路复用 消除应用层队头阻塞,连接复用 TCP 层队头阻塞仍然存在 TCP 拥塞控制参数、丢包率
流优先级 关键请求优先处理 优先级配置错误导致请求饿死 Envoy 的优先级策略和流调度
HPACK 头部体积大幅减小,传输快 动态表同步开销,代理修改头部破坏缓存 代理的头部修改频率、HPACK 表大小