SETTINGS 与优先级
六个 SETTINGS 参数、ACK 机制,以及优先级树的废弃与 RFC 9218 扩展优先级。
作者 David更新于 第 7 篇(共 16 篇)
SETTINGS 帧
连接级参数协商,流 ID MUST 为 0。
机制要点:
- 不是握手,是单向声明:每一端各自声明「我这边的接收能力」。双方的值互相独立,无需一致。
- 载荷是若干 6 字节条目:2 字节标识符 + 4 字节值。载荷长度不是 6 的倍数 →
FRAME_SIZE_ERROR。 - 接收方 MUST 立即(在处理后续帧之前)应用这些值,并回一个置
ACK标志(0x01)的空SETTINGS。 - 带
ACK的帧载荷长度必须为 0,否则FRAME_SIZE_ERROR。 - 长时间收不到 ACK MAY 以
SETTINGS_TIMEOUT关闭连接。 - 未知标识符 MUST 被忽略(扩展点)。
六个标准参数
| ID | 名称 | 默认值 | 语义 |
|---|---|---|---|
0x01 | HEADER_TABLE_SIZE | 4096 | 对端 HPACK 动态表上限(字节) |
0x02 | ENABLE_PUSH | 1 | 是否允许服务端推送;只能取 0/1,其他值 → PROTOCOL_ERROR |
0x03 | MAX_CONCURRENT_STREAMS | 无限 | 对端可同时打开的流数 |
0x04 | INITIAL_WINDOW_SIZE | 65535 | 流级流量控制初始窗口;> 2^31−1 → FLOW_CONTROL_ERROR |
0x05 | MAX_FRAME_SIZE | 16384 | 可接收的最大帧载荷;合法范围 16384 – 16777215,越界 → PROTOCOL_ERROR |
0x06 | MAX_HEADER_LIST_SIZE | 无限 | 可接收的字段列表未压缩大小上限(含每字段 32 字节开销);仅为建议 |
生产调优的三个重点:
INITIAL_WINDOW_SIZE—— 默认 65535 在高 BDP 链路上严重限速,通常调到 MB 级。MAX_CONCURRENT_STREAMS—— 默认无限意味着无防护,必须设有限值(常见 100–128),否则易受流洪泛。MAX_HEADER_LIST_SIZE—— 默认无限,是 HPACK 炸弹的防线,应显式设置。
优先级:一段被推翻的设计
RFC 7540 的优先级树(已废弃)
原设计中,PRIORITY 帧与 HEADERS 的优先级字段可构建一棵依赖树:
- 每个流可声明依赖另一个流(
Stream Dependency)。 - 同层兄弟按权重(1–256)按比例分配带宽。
- 支持独占依赖(
E标志),把原有兄弟全部改挂到自己名下。
RFC 9113 已将其全部废弃(deprecated)。废弃原因,逐条:
| 问题 | 说明 |
|---|---|
| 过度复杂 | 服务端要维护每连接一棵可变树,含已关闭流的「幽灵节点」 |
| 实现分歧大 | 各服务端调度策略互不兼容,客户端无法预期效果 |
| 浏览器各行其是 | Chrome 用线性链、Firefox 用分组树,服务端难以同时优化 |
| 收益不明 | 实测多数场景与简单的 FIFO/轮转差别不大 |
| 攻击面 | 恶意构造的深树消耗服务端内存与 CPU |
现状:端点仍 MUST 能解析这些字段(向后兼容,收到即忽略),但 SHOULD NOT 再生成。多数现代服务端直接无视优先级树。
RFC 9218 扩展优先级(现行方案)
替代方案把优先级从「二进制帧里的树」改成了普通的 HTTP 字段,且 h2 与 h3 通用:
priority: u=1, i两个参数(结构化字段语法):
| 参数 | 类型 | 取值 | 语义 |
|---|---|---|---|
u | 整数 | 0–7,默认 3 | 紧急度,数值越小优先级越高 |
i | 布尔 | 默认 false | incremental:为真表示可渐进式呈现(如渐进 JPEG、HTML 流式渲染) |
用法:
- 客户端在请求的
priority字段中声明。 - 服务端可在响应中用
priority字段覆盖(服务端更清楚资源性质)。 - 也可用
PRIORITY_UPDATE帧(h2 类型0x10,h3 类型0xF0700/0xF0701)在请求发出后动态改。 i=?1的同优先级流应轮转调度(让多个可渐进资源同时推进);i=?0的应顺序完成(一个一个来,早点可用)。
设计上的进步:无状态、可读、可被中间件理解、h2/h3 统一——而不是一棵需要双方精确同步的树。
下一篇:连接管理与错误码。