土法炼钢兴趣小组的算法知识备份

【Envoy 数据面】连接池、熔断与 Outlier:路由正确为何仍 503

文章导航

分类入口
networkproxy
标签入口
#envoy#connection-pool#circuit-breaker#outlier-detection#503#upstream#v1.39

目录

Cluster / LB 已经能选出一台「健康」主机,但现场排障里大量 503 并不来自「路由指错 cluster」,而来自 连接池耗尽、熔断打开、outlier 把主机剔出可调度集合。本文钉这三层资源语义,说明它们如何在「RDS/CDS 看起来正确」时仍让 Router 对外失败,并为 xDS 资源树 里「有 cluster 无可用 endpoint」的配置依赖做铺垫。

本文是「Envoy / 数据面代理内核」系列第 8 篇(共 16 篇)。→ 系列目录

篇目 核心内容
第 7 篇 · Cluster / LB 选主层次
第 8 篇 · 连接池 / 熔断 / outlier 限额如何卡死上游
第 9 篇 · xDS 资源树 LDS→EDS 依赖

上一篇Cluster 与负载均衡 · 下一篇xDS 资源树

版本锚定:Envoy v1.39.0 Connection poolingCircuit breakingOutlier detection。无伪造 stats 输出。

本篇不展开:LB 算法与 subset 键设计(第 7 篇)、xDS 推送顺序(第 9 篇)、全局/本地 rate limit 扩展(第 13 篇)。只回答「选主之后,资源限额与被动驱逐如何让请求失败」。


一、失败轴:不是只有「上游挂了」

Router 在选中 cluster 后向连接池要一条可发流的上游连接。任一环节拒绝,下游常见表现是 503,并可能带 x-envoy-overloaded(熔断 / maintenance 路径,见 Router 文档)。归因前先分轴:

典型计数 / 信号 含义
路由 no_route / no_cluster 根本没进到合法上游名
池 / 熔断 upstream_cx_overflowupstream_rq_pending_overflowupstream_rq_retry_overflow 资源配额打满
Outlier 驱逐事件日志 / 主机从 LB 集合消失 被动认为该主机异常
真上游错误 上游 5xx(未必变 503) 已出池、已收到响应

本篇关注中间两行。

flowchart TD
  router["Router"] --> lb["LB picks host"]
  lb --> cb{"Circuit breaker<br/>room?"}
  cb -->|"no"| fail503["503 / overloaded"]
  cb -->|"yes"| pool["Conn pool acquire"]
  pool -->|"pending full"| fail503
  pool -->|"ok"| up["Upstream attempt"]
  up --> od["Outlier may eject host"]

二、连接池:协议抽象与「有多少个池」

官方 Connection pooling:HTTP 流量使用抽象连接池,屏蔽 HTTP/1.1 与 HTTP/2·3 是否真多路复用。

协议 行为要点
HTTP/1.1 按需建连;不用 pipelining,一连接同时服务一请求,避免上游断开时重置过多下游
HTTP/2 / HTTP/3 多路复用直至 max concurrent streams / max requests per connection;忙则标 busy,可再建连直至熔断上限

池的数量不是「每 cluster 一个」:

含义:电路熔断的「最大连接数」是 跨 Worker 共享的 cluster 限额(最终一致,允许竞态短暂超过),但池实例是每线程的——排障时看全局 upstream_cx_active 的同时要意识到局部池状态并不在一个锁下。

主动或被动健康检查导致主机从 available → unavailable 时,该主机相关连接池连接会被关闭;主机回到旋转后再建新连接,以规避坏 ECMP 路径等粘滞问题。


三、Circuit breaking:分布式限额

官方强调:Envoy 在网络层施加完全分布式(各代理不协调)的熔断,默认开启且带温和默认值(例如每 cluster 1024 连接量级);要「关掉」需把阈值调到允许的最大值。

cluster × priority 跟踪的典型限额:

限额 溢出计数(文档名) 直觉
Max connections upstream_cx_overflow 到该 cluster 所有主机的连接上限;drain 中连接仍计数
Max pending requests upstream_rq_pending_overflow 等不到就绪连接时的排队上限
Max requests upstream_rq_active_overflow 集群飞行中请求上限
Max pending retries upstream_rq_retry_overflow 飞行中重试上限;更推荐 retry budget
Max concurrent connection pools upstream_cx_pool_overflow 池实例数上限(如 original_dst 可制造大量池)

注意文档细节:即使连接熔断已溢出,Envoy 仍保证 LB 选中的主机至少有一条连接——因此 upstream_cx_active 可以高于「最大连接」配置,理论上界与「每 endpoint × 每池」有关。Worker 之间共享限额但是 eventually consistent,短时超过阈值可能发生。

对 HTTP/2,若未限制并发流,请求多路复用在同一连接上,pending 熔断往往只在尚无连接时触发——不要用 HTTP/1 直觉硬套。

路由层的 priority routingdefault / high)会使用不同的连接池与熔断设置:即便 HTTP/2,到同一上游主机也可能是两条物理连接。这与 EDS 的 priority 档位相关但配置面不同——一个是请求优先级,一个是 endpoint 拓扑档;两者都会放大「看起来同一个 cluster」下的资源记账维度。


四、Outlier detection:被动摘除

Outlier 是 passive health checking:根据连续失败、成功率、延迟等把主机标为不健康并移出正常 LB 集合(panic 场景除外)。主动 HC 可并行;过滤器必须上报错误——HTTP Router、TCP Proxy、Redis、Thrift 等支持。

错误分两类(可 split_external_local_origin_errors):

默认不拆分时,本地与外部计入同一桶,对比 consecutive_5xx 等阈值。驱逐算法要点:

  1. 判定 outlier。
  2. 若已驱逐比例达到 max_ejection_percent,则不再驱逐。
  3. 驱逐时长 ≈ base_ejection_time × 连续驱逐次数,封顶 max_ejection_time;恢复后乘数随健康间隔递减。

检测类型包括 consecutive 5xx / gateway failure(502–504)/ local origin failure、success rate、failure percentage、以及 x-envoy-degraded 的 degraded(仍在旋转但降权)。共享同一 cluster 的多条 filter chain 会共享驱逐结果——一条链因 HTTP 5xx 踢掉的主机,另一条 TCP 链也会受影响。

gRPC 路径上,outlier 默认把 grpc-status 映到 HTTP 语义再计入;若业务用非 5xx 的 HTTP 码表示失败,需在 cluster extension_protocol_options 的 outlier 映射里显式把匹配响应报成 5xx,否则被动检测会当成成功。

与主动 HC:默认成功主动检查可 uneject;若探活不代表数据面业务成功,可能过早拉回坏主机,可关 successful_active_health_check_uneject_host


五、排障口诀:路由对仍 503

  1. 先排除 no_route / no_cluster(第 6 篇)。
  2. 看 cluster 熔断剩余与 *_overflow 计数是否在爬升。
  3. 看 outlier 是否把多数主机驱逐到只剩空集或 panic 行为。
  4. 再看 subset / priority 是否把集合收成空(第 7 篇)。
  5. 最后才是上游进程真死——那往往是 5xx 透传或连接失败,而不一定是 Envoy 合成的 overloaded 503。

配置层:熔断过小 + 重试无预算 = 自激振荡;outlier 过敏 + 小集群 = 一次抖动驱逐过半主机。调参必须按 priority 分流的独立阈值 理解,不能只看「cluster 平均值」。

可选开启 outlier 事件日志(Cluster manager 级配置,protobuf OutlierDetectionEvent):全局计数只能说明「有驱逐」,不足以回答「哪台、因为哪种检测」。生产排障应优先事件流,再回看 consecutive_* / success rate 阈值是否与错误分类(是否 split local/external)一致。


六、谱系、争论与开放问题

谱系:熔断作为分布式系统快速失败手段,在微服务代理层被做成每跳强制配额(Envoy circuit breaking 文档开篇立场),避免每个应用各自实现不一致。Outlier 延续「被动探测 + 短暂隔离」运维传统,与主动探活组成完整健康方案。

争论:默认熔断阈值是否应更保守。过宽等于未保护;过窄在扇出服务上制造系统性 503。官方选择「默认开启 + 温和默认 + 可观测剩余配额」,把精细度留给运维——这是工程默认,不是理论最优。

开放问题:跨 Worker 最终一致限额在超高并发短连接场景下的超调幅度,缺乏本系列可引用的本机实测;大规模 EDS 抖动下 outlier 与主动 HC 谁先稳态,见第 9–11 篇与排障篇。


七、参考资料

规范 / 官方文档(A)

源码(A)

站内

实验台账


八、小结

  1. 连接池按线程 / 协议 / socket 选项分池;熔断限额跨 Worker 共享但最终一致。
  2. Circuit breaker 溢出是「路由正确仍 503」的第一嫌疑;重试有独立上限与 budget。
  3. Outlier 被动摘除主机,可与主动 HC 叠加;共享 cluster 则共享驱逐后果。
  4. 资源对象本身由 xDS 树挂出——下一篇讲 LDS→RDS→CDS→EDS 命名与依赖顺序。

系列目录 · 上一篇:Cluster 与负载均衡 · 下一篇:xDS 资源树

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .