4. Envoy HTTP/2 流控机制:初始窗口大小、动态窗口更新、RST_STREAM 与 GOAWAY 帧在流控中的作用
在 Envoy 多租户场景中,HTTP/2 流控是防止单个租户的突发流量耗尽代理缓冲区、导致其他租户请求被饿死的关键防线。Envoy 作为数据面代理,必须精确管理 HTTP/2 的流控参数,以确保在故障域内实现公平的资源分配和快速的故障恢复。本节将深入剖析 HTTP/2 流控的核心机制,并阐述其在 Envoy 中的具体实现与作用。
4.1 HTTP/2 流控模型概述
HTTP/2 采用基于信用的流控模型,接收方通过 WINDOW_UPDATE 帧向发送方通告其可接收的数据量。Envoy 在上下游连接中分别维护两个级别的流控窗口:
- 连接级窗口(Connection Window):控制整个 HTTP/2 连接的总流量。
- 流级窗口(Stream Window):控制单个 HTTP/2 流(即单个请求/响应)的流量。
Envoy 的流控策略直接影响租户隔离效果。若窗口设置过大,单个租户的突发流量可能占满共享缓冲区;若窗口过小,则会增加 RTT 延迟,降低吞吐量。
4.2 初始窗口大小:租户隔离的第一道防线
HTTP/2 的 SETTINGS_INITIAL_WINDOW_SIZE 参数定义了每个流在建立时的初始窗口大小。Envoy 允许通过配置动态调整此值,以适应不同租户的流量特征。
| 配置参数 | 默认值 | 租户隔离建议 | 说明 |
|---|---|---|---|
initial_stream_window_size |
65535 (64KB) | 16KB - 32KB | 减小初始窗口可限制单个流的突发量,防止租户独占带宽 |
initial_connection_window_size |
65535 (64KB) | 256KB - 1MB | 连接窗口应大于流窗口之和,避免连接级瓶颈 |
max_concurrent_streams |
100 | 10 - 50 | 限制租户可同时打开的流数量,配合窗口大小实现精细控制 |
initial_stream_window_size 设置得过小(如 < 8KB),会导致高频的 WINDOW_UPDATE 帧交互,增加 CPU 开销和延迟。建议在租户隔离测试中逐步调优,找到延迟与公平性的平衡点。
4.3 动态窗口更新:自适应流量调节
Envoy 不会被动等待窗口耗尽才发送 WINDOW_UPDATE。它采用基于缓冲区水位的动态更新策略,在接收方缓冲区未满时提前释放信用,以维持高吞吐量。
Envoy 的窗口更新逻辑遵循以下步骤:
- 数据到达:接收方(Envoy 或上游)将数据写入缓冲区。
- 缓冲区水位检查:Envoy 监控缓冲区使用量,当低于低水位线(low_watermark)时,触发窗口更新。
- 信用计算:Envoy 计算可释放的信用量,通常为
当前窗口 - 已消费数据 + 已处理数据。 - 发送 WINDOW_UPDATE:Envoy 向发送方发送 WINDOW_UPDATE 帧,增加可用窗口。
connection_window_dynamic_max 和 stream_window_dynamic_max 配置,允许窗口大小根据连接延迟和丢包率自动调整,实现类似 TCP 拥塞控制的动态行为。
4.4 RST_STREAM 帧:快速故障隔离
RST_STREAM 帧用于立即终止一个 HTTP/2 流。在 Envoy 多租户场景中,RST_STREAM 是隔离故障租户、防止影响扩散的关键工具。
Envoy 在以下场景会主动发送 RST_STREAM:
- 租户超时:当某个租户的请求处理超过配置的超时时间(如
request_timeout或idle_timeout)。 - 上游连接失败:后端服务返回 5xx 错误或连接断开,Envoy 立即重置对应流。
- 流控违规:接收方检测到发送方超出窗口限制(如
FLOW_CONTROL_ERROR)。 - 租户资源耗尽:当租户的并发流数或内存使用超过配额时,Envoy 发送 RST_STREAM 拒绝新请求。
| 错误码 | 触发场景 | 租户隔离影响 |
|---|---|---|
NO_ERROR (0) |
正常流结束前的优雅重置 | 无影响,流正常关闭 |
PROTOCOL_ERROR (1) |
HTTP/2 协议解析失败 | 隔离恶意或畸形请求 |
FLOW_CONTROL_ERROR (3) |
发送方超出窗口限制 | 防止单个租户滥用流控 |
STREAM_CLOSED (5) |
在已关闭的流上收到数据 | 清理残留数据,释放资源 |
REFUSED_STREAM (7) |
服务端负载过高,拒绝新流 | 客户端可安全重试,实现优雅降级 |
max_requests_per_connection 和 max_concurrent_streams。当租户超过限制时,Envoy 发送 RST_STREAM 并记录告警,实现租户级熔断。
4.5 GOAWAY 帧:连接级优雅关闭
GOAWAY 帧用于通知对端当前 HTTP/2 连接即将关闭。与 RST_STREAM 不同,GOAWAY 是连接级操作,影响所有流。Envoy 在以下场景使用 GOAWAY:
- 连接 draining:当 Envoy 需要关闭连接进行升级或维护时,发送 GOAWAY 通知客户端停止创建新流。
- 租户隔离边界:在多租户场景中,当某个租户的连接出现严重错误(如内存泄漏、死循环),Envoy 可以发送 GOAWAY 关闭整个连接,防止影响其他租户。
- 负载均衡:Envoy 在重新均衡连接时,通过 GOAWAY 优雅地迁移流量。
GOAWAY 帧包含一个 last_stream_id 字段,标识接收方将处理的最后一个流 ID。所有大于此 ID 的流将被拒绝。Envoy 利用此机制实现分阶段的连接关闭:
- 发送 GOAWAY:Envoy 发送 GOAWAY 帧,指定 last_stream_id 为当前最大流 ID。
- 等待处理完成:Envoy 继续处理已接收的流,但拒绝新流。
- 超时强制关闭:若在
drain_timeout内未完成,Envoy 强制关闭连接。
HttpConnectionManager 中,可以为不同租户配置不同的 drain_timeout。高优先级租户获得更长的 drain 时间,确保其请求被完整处理;低优先级租户则快速关闭,释放资源。
4.6 流控机制协同工作:租户隔离恢复流程
在故障域恢复场景中,Envoy 的 HTTP/2 流控机制协同工作,实现快速隔离和恢复:
| 阶段 | 触发条件 | Envoy 动作 | 流控机制 |
|---|---|---|---|
| 1. 故障检测 | 租户 A 的请求超时或错误率飙升 | 标记租户 A 为故障状态 | — |
| 2. 快速隔离 | 租户 A 的流超过配额 | 发送 RST_STREAM 拒绝新流 | RST_STREAM + 流级窗口 |
| 3. 连接级保护 | 租户 A 的故障影响共享连接 | 发送 GOAWAY 关闭连接 | GOAWAY + 连接级窗口 |
| 4. 资源回收 | 连接关闭后 | 重置窗口状态,释放缓冲区 | 窗口重置 |
| 5. 恢复 | 故障解除或超时后 | 重新建立连接,恢复默认窗口 | 初始窗口 + 动态更新 |
drain_timeout 内未完成,Envoy 会强制关闭连接,可能导致数据丢失。建议为关键租户设置较长的 drain 超时(如 30s),并配合重试机制。
通过精确控制初始窗口大小、动态窗口更新、RST_STREAM 和 GOAWAY 帧,Envoy 能够在多租户环境中实现细粒度的流量隔离和快速故障恢复,确保单个租户的异常不会扩散到整个故障域。