4. 连接断开类型:主动断开、被动断开、空闲超时断开、健康检查失败断开

在 Envoy 代理的日常运行中,连接断开是触发重试机制的直接原因。理解不同类型的连接断开,有助于精准配置重试策略,避免无效重试或重试风暴。Envoy 将连接断开归纳为四种核心类型:主动断开、被动断开、空闲超时断开和健康检查失败断开。每种类型在协议栈中的触发点、可重试性以及性能影响均有显著差异。

调优要点:并非所有断开都适合重试。主动断开通常由客户端或上游正常关闭引起,重试无意义;而被动断开(如 RST 包)往往暗示上游异常,是重试策略的主要作用对象。

4.1 四种断开类型对比

断开类型 触发场景 TCP 层表现 HTTP 层表现 Envoy 默认重试行为
主动断开 客户端/上游正常关闭连接 FIN 包(四次挥手) Connection: close 头 不重试
被动断开 上游崩溃、超时、拒绝请求 RST 包 5xx 状态码、流重置 可重试(默认最多 1 次)
空闲超时断开 连接空闲超过 idle_timeout FIN 或 RST(取决于实现) 流重置 不重试(连接已回收)
健康检查失败断开 主动健康检查判定上游不健康 Envoy 主动发送 RST 无(健康检查独立于数据面) 不重试(上游已被剔除)

4.2 主动断开(Active Close)

主动断开是指连接的一方在完成数据传输后,按照协议规范正常关闭连接。在 TCP 层面表现为发送 FIN 包,完成四次挥手。Envoy 在以下场景会触发主动断开:

  • 客户端主动关闭:HTTP/1.1 请求完成后,客户端发送 Connection: close 头。
  • 上游服务器主动关闭:上游处理完响应后,关闭连接以回收资源。
  • Envoy 自身连接管理:达到最大连接数限制时,Envoy 会主动关闭最老的空闲连接。

主动断开是预期内的行为,Envoy 不会将其视为错误,因此不会触发重试。如果重试策略错误地将主动断开纳入重试范围,会导致大量无效连接建立,增加延迟和资源消耗。

4.3 被动断开(Passive Close / RST)

被动断开是连接因异常情况被强制终止,TCP 层表现为发送 RST 包。这是 Envoy 重试机制最关注的断开类型。常见触发原因包括:

  • 上游进程崩溃:上游服务突然退出,操作系统内核发送 RST。
  • 上游超时:上游在 upstream_request_timeout 内未响应,Envoy 重置流。
  • 上游拒绝连接:上游连接池已满或处于过载保护状态。
  • 协议错误:上游返回格式错误的 HTTP 响应或非法帧。
性能影响:被动断开通常伴随连接池中的连接失效。Envoy 需要立即从连接池中移除该连接,并触发重试逻辑。如果被动断开率过高(>5%),应优先排查上游稳定性,而非单纯增加重试次数。

4.4 空闲超时断开(Idle Timeout)

Envoy 为每个连接维护一个空闲计时器。当连接在 idle_timeout 时间内没有任何数据传输时,Envoy 会主动断开该连接以释放资源。这是连接池管理的关键机制。

关键配置参数:

参数 默认值 推荐值(高并发场景) 说明
idle_timeout 1 小时 5-10 分钟 连接空闲超过此时间即断开
max_connection_duration 无限制 30 分钟 连接最大存活时间,防止长连接泄漏

空闲超时断开是正常资源回收行为,Envoy 不会将其视为上游错误,因此不触发重试。调优时需注意:过短的 idle_timeout 会导致频繁断开和重建连接,增加 TCP 握手开销;过长的 idle_timeout 则可能占用大量内存和文件描述符。

4.5 健康检查失败断开(Health Check Failure)

Envoy 通过主动健康检查(Active Health Check)定期探测上游端点。当端点连续失败次数超过 unhealthy_threshold 时,Envoy 将其标记为不健康,并主动断开该端点上的所有现有连接。

健康检查断开的特点:

  • 触发方式:由 Envoy 的健康检查线程主动发起,独立于数据面请求。
  • 断开范围:断开该上游端点上的所有连接,而非单条连接。
  • 重试行为:Envoy 不会对健康检查失败的连接进行重试,因为上游已被从负载均衡池中剔除。
  • 恢复机制:当健康检查再次成功(连续成功次数达到 healthy_threshold),端点重新加入池,新连接开始建立。
避坑指南:健康检查失败断开可能导致连接池雪崩。如果健康检查间隔过短(如 1 秒),且上游短暂抖动,Envoy 可能快速剔除大量端点,导致剩余端点瞬时压力激增。建议将健康检查间隔设置为 5-10 秒,并配合 panic_threshold(恐慌阈值)使用。

4.6 断开类型与重试决策流程

Envoy 在决定是否重试时,会按以下流程判断断开类型:

  1. 检查是否为主动断开:如果是 FIN 包或 Connection: close,直接返回,不重试。
  2. 检查是否为健康检查失败断开:如果上游已被标记为不健康,不重试,直接返回 503。
  3. 检查是否为空闲超时断开:如果连接因空闲超时被回收,不重试。
  4. 检查是否为被动断开:如果是 RST 包或 5xx 响应,进入重试逻辑,检查重试次数、重试预算和重试策略。
Envoy 连接断开类型与重试决策流程 连接断开事件 主动断开?(FIN/Connection:close) 不重试 否 健康检查失败断开? 不重试 否 空闲超时断开? 不重试 否 被动断开 (RST/5xx) 进入重试逻辑 调优提示 仅被动断开进入重试逻辑 其他三种断开均不重试

4.7 性能调优建议

  • 区分断开类型监控:在 Envoy 的 stats 中,通过 downstream_cx_destroy 和 upstream_cx_destroy 指标区分主动与被动断开。如果被动断开占比超过 20%,应优先优化上游稳定性。
  • 空闲超时与连接池大小联动:当连接池较大(如 100+)时,适当缩短 idle_timeout(如 5 分钟),避免大量空闲连接占用内存。
  • 健康检查失败断开后的重试保护:配置 retry_budget 和 panic_threshold,防止健康检查抖动导致的重试风暴。
  • 避免对主动断开重试:在 retry_on 配置中,不要包含 connect-failure 之外的主动断开相关条件。
案例:某电商平台在促销期间出现大量 503 错误。排查发现,Envoy 的 idle_timeout 设置为 10 秒,导致连接频繁断开重建。同时,健康检查间隔为 2 秒,上游短暂抖动时大量端点被剔除。优化方案:将 idle_timeout 调整为 5 分钟,健康检查间隔调整为 10 秒,并启用 panic_threshold: 50%。优化后 503 错误率从 8% 降至 0.3%。