Envoy 降级端点(Degraded Endpoints):负载溢出机制与 detect_degraded_hosts 源码解析
2026/9/14 17:17:40 网站建设 项目流程

Envoy 降级端点(Degraded Endpoints):负载溢出机制与 detect_degraded_hosts 源码解析

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

本篇基于 Envoy 官方架构文档 Degraded endpoints 展开,系统讲解“降级端点”在负载均衡中的定位:它如何与优先级溢出(priority spillover)协同工作、流量在 healthy/degraded/unhealthy 三类主机间如何分配,以及如何通过主动健康检查头与异常检测(outlier detection)两种途径把端点标记为降级。读完本文,你将掌握x-envoy-degraded头、detect_degraded_hosts配置的完整用法,并能从 Envoy 源码层面理解降级标记的置位、退避与清除逻辑。

1. 什么是降级端点:介于“健康”与“剔除”之间的第三状态

Envoy 支持将某些上游端点标记为降级(degraded):这些主机仍然能够接收流量,但只有当健康主机不足以承载全部负载时,才会收到流量。

从 Envoy 上游主机头文件 的注释可以看到这一语义的准确定义:主机“是健康的,但处于降级状态。它能够提供流量,但应优先选择未降级的主机”。这与 outlier detection 的剔除(ejection)有本质区别:

维度降级(degraded)剔除(ejected)
是否参与负载均衡是,始终保留在轮换集中否(panic 场景除外)
接收流量的条件健康主机不足时才接收不接收流量
标记方式x-envoy-degraded连续 5xx / 成功率统计等
恢复方式退避期结束后自动清除退避期结束或主动健康检查通过

异常检测文档 中“Degraded Host Detection”一节明确强调:“与被剔除的主机不同,降级主机保留在负载均衡轮换中,只是被降低优先级(deprioritized),仅在可用健康主机不足时才接收流量”。

从源码结构看,Envoy 通过一组健康标志位(health flag)区分主机状态,见 upstream.h:DEGRADED_ACTIVE_HC(主动健康检查降级)、DEGRADED_EDS_HEALTH(由 EDS 标记的降级)、以及本次重点的DEGRADED_OUTLIER_DETECTION, 0x400(由异常检测标记的降级)。

2. 流量分配:降级主机如何“接住”溢出的负载

官方文档给出的核心机制描述是:对降级主机的路由可以类比为路由到低一级优先级的流量,但关键差异在于——降级主机会计入其原始优先级的健康占比,用于计算流量溢出(traffic spillover)。当可用健康主机的占比不再足以处理 100% 的负载时,流量会以与优先级溢出(priority spillover)相同的机制逐渐流向降级主机,从而保证“随着必要性增加,流量被逐步(gradually)转移到降级主机”,而不是发生突变。

官方文档给出了一个单优先级(P=0)集群的流量分配示例表,完整继承如下:

P=0 healthy/degraded/unhealthy 占比流向 P=0 健康主机的流量流向 P=0 降级主机的流量
100%/0%/0%100%0%
71%/0%/29%100%0%
71%/29%/0%99%1%
25%/65%/10%35%65%
5%/0%/95%100%0%

这张表可以读出三条规律:

  1. 健康主机足够时,降级主机不接流量(第一行:100% 健康,降级流量为 0%);
  2. 健康占比下降时,流量按溢出比例渐进地让渡给降级主机(25%/65%/10% 一行:35% 给健康、65% 给降级);
  3. 没有降级主机可溢出时,流量仍全部记到健康主机上(第二、五行),即使集群整体健康占比并不高——溢出目标是按“是否存在降级主机”决定的。

这套溢出计算复用了优先级溢出的既有机制,因此与 优先级负载均衡 的行为保持一致;而当溢出连降级主机都不够时,还会进入 panic 阈值 场景,允许流量打向不健康主机。

3. 标记端点为降级的两种途径

官方文档指出,端点可以通过以下两种方式被标记为降级:

  1. 主动健康检查(active health checking):上游主机在健康检查响应中返回特殊响应头x-envoy-degraded
  2. 异常检测(outlier detection,被动健康检查):开启detect_degraded_hosts字段,并由上游主机在正常业务响应中返回x-envoy-degraded头。

3.1 途径一:HTTP 健康检查器 + x-envoy-degraded 头

健康检查架构文档 的“Degraded health”一节说明:使用 HTTP 健康检查器时,上游主机可以返回x-envoy-degraded响应头来告知健康检查器该主机已降级。该途径由 Envoy 的主动健康检查组件周期性探测实现,对应主机上的DEGRADED_ACTIVE_HC标志位,且 健康检查事件日志 会分别记录degraded_healthy_hostno_longer_degraded_host事件。

3.2 途径二:outlier_detection.detect_degraded_hosts

被动途径通过集群配置envoy.config.cluster.v3.OutlierDetection消息启用。该字段定义在 outlier_detection.proto,其完整注释为:

If set to true, outlier detection will mark hosts as degraded when they return thex-envoy-degradedheader. Degraded hosts are deprioritized in load balancing but are not ejected from the cluster. The degraded state is cleared using the same backoff algorithm as ejection, with the degradation period calculated asbase_ejection_timemultiplied by the number of times the host has been marked as degraded, capped bymax_ejection_time. Defaults to false.

要点有三:字段为BoolValue包装类型,默认false(即默认关闭);降级主机不会被剔除,只会被降优先级;降级状态沿用剔除的退避算法清除,降级时长 =base_ejection_time × 被标记次数,并以max_ejection_time封顶。该能力的相关条目出现在 1.38.0 版本 changelog 中,使用时请确认 Envoy 版本支持该字段。

3.3 配置示例

结合上述语义,一个启用被动降级检测的集群配置如下(字段含义均与 proto 注释一致):

clusters: - name: service_backend connect_timeout: 5s type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: service_backend endpoints: - lb_endpoints: - endpoint: address: socket_address: { address: 10.0.0.1, port_value: 8080 } - endpoint: address: socket_address: { address: 10.0.0.2, port_value: 8080 } outlier_detection: interval: 10s # 剔除/降级状态扫描间隔,默认 10s base_ejection_time: 30s # 同时作为降级退避基准时长,默认 30s max_ejection_time: 300s # 剔除与降级时长的封顶值,默认 300s max_ejection_percent: 10 # 剔除占比上限(对降级无约束,降级不计入剔除) detect_degraded_hosts: true

注意intervalbase_ejection_timemax_ejection_time三个参数同时服务于剔除退避和降级退避两条路径,调参时需一并考虑:interval决定多频繁地执行一次“是否可以清除降级标记”的检查。

4. 源码级实现:置位、退避与清除

降级检测的完整实现位于 outlier_detection_impl.cc,可以沿着“上报 → 置位 → 退避 → 清除”四步阅读。

4.1 结果上报:ExtOriginRequestDegraded

过滤器(如 HTTP router)在响应携带x-envoy-degraded头时,向上游报告Result::ExtOriginRequestDegraded。在两种错误分桶模式下,该结果都会被转换为降级动作,然后按成功响应记账

  • 不分桶模式 putResultNoLocalExternalSplit:if (result == Result::ExtOriginRequestDegraded) { detector->setHostDegraded(host); },随后若未显式提供状态码则映射为200 OK
  • 分桶模式 putResultWithLocalExternalSplit:注释写明“Mark host as degraded, then process as successful response”,同样调用setHostDegraded后按 200 记账。

这一设计保证了携带降级头的响应不会被误计入 5xx 连续错误,从而不会触发剔除。

4.2 置位:工作线程 → 主线程,退避计数递增

由于结果来自各 worker 线程,检测器先经 setHostDegraded 做开关检查(detectDegraded()为 false 时直接返回),再 post 到主线程 执行 setHostDegradedMainThread。主线程中的关键逻辑:

if (!host->healthFlagGet(Host::HealthFlag::DEGRADED_OUTLIER_DETECTION)) { updateDetectedEjectionStats(envoy::data::cluster::v3::DEGRADED); host_monitors_[host]->degrade(time_source_.monotonicTime()); // 生成随机 jitter,防止大量主机同时解除降级引发连接风暴 const std::chrono::milliseconds jitter = std::chrono::milliseconds(random_generator_() % (max_eject_time_jitter + 1)); host_monitors_[host]->setJitter(jitter); // 退避计数递增,且受 max_ejection_time 封顶保护 if ((host_monitors_[host]->degradeTimeBackoff() * base_eject_time) < (max_eject_time + base_eject_time)) { host_monitors_[host]->degradeTimeBackoff()++; } if (event_logger_) { event_logger_->logEject(host, *this, envoy::data::cluster::v3::DEGRADED, true); } runCallbacks(host); }

可以看到:只有当前未处于降级态时才会重复计数(避免同一状态期间 backoff 无限增长);jitter 由max_ejection_time_jitter控制,用于打散解除降级时刻;事件日志以DEGRADED类型区分于真实剔除(logEject(host, ..., DEGRADED, true),enforced 恒为 true,因为降级必然生效)。相关事件消息定义在 outlier_detection_event.proto。

值得一提的是,检测器对DEGRADED类型显式断言不得走剔除辅助路径(见 enforceEjection 中的IS_ENVOY_BUG("enforceEjection() should not be called for DEGRADED type")),从代码上保证了“降级不是剔除”的语义边界。

4.3 清除:interval 定时器驱动,min(base × backoff, max) + jitter

每次interval定时器到期,onIntervalTimer 会遍历所有主机并调用 checkHostForUndegrade:

if (!config_.detectDegraded() || !host->healthFlagGet(Host::HealthFlag::DEGRADED_OUTLIER_DETECTION)) { return; } ... if ((std::min(base_eject_time * monitor->degradeTimeBackoff(), max_eject_time) + jitter) <= (now - monitor->lastDegradedTime().value())) { host->healthFlagClear(Host::HealthFlag::DEGRADED_OUTLIER_DETECTION); monitor->undegrade(time_source_.monotonicTime()); runCallbacks(host); if (event_logger_) { event_logger_->logUneject(host); } }

即:降级时长达到min(base_ejection_time × backoff, max_ejection_time) + jitter后清除DEGRADED_OUTLIER_DETECTION标志并触发主机集变化回调(负载均衡器据此重新计算各优先级 healthy/degraded 占比与溢出分配)。此外,onIntervalTimer末尾还有一段与剔除退避对称的逻辑:对未处于降级态且距上次解除已过一个interval的主机,degradeTimeBackoff()递减 1,使健康主机的下次降级时长回到基准值(见 L911-L926)。

退避语义与剔除完全同构:连续多次被标记为主机 → 降级停留时间逐次拉长(30s、60s、90s……直至封顶 300s),避免“反复降级—反复恢复”的震荡;而一旦在检查窗口内保持非降级状态,backoff 计数回落,下次降级回到最短时长。

5. 可观测性:如何确认某主机已降级

  • Admin/clusters视图:host_utility.cc 在拼接主机健康状态字符串时,会依次追加degraded_active_hcdegraded_eds_healthdegraded_outlier_detection等片段。因此通过DEGRADED_OUTLIER_DETECTION标志位降级的主机,在 admin 接口的主机健康展示中可以看到degraded_outlier_detection字样,可直接区分三种降级来源。
  • 集群统计:主机集统计中包含membership_degradedgauge(定义见 upstream.h),upstream_impl.cc 中在每个优先级更新时统计host_set->degradedHosts().size()并刷新该值,可据此监控集群内降级主机数量。
  • 主机集合 APIHostSet提供 degradedHosts() / degradedHostsPerLocality() 等接口暴露当前降级主机集合,负载均衡器正是基于这些集合与健康主机集合做溢出分配;对应的 locality 级负载结构DegradedLoad degraded_priority_load_定义在 types.h。
  • 事件日志:若配置了 ClusterManager 级别的 outlier detection 事件日志,每次降级与解除降级都会落盘一条OutlierDetectionEvent,其中type字段为DEGRADED

6. 实践要点与适用前提

  1. 默认关闭detect_degraded_hosts默认false,被动降级检测必须显式开启;主动健康检查路径则要求上游在健康检查响应中携带x-envoy-degraded头。
  2. 降级不是剔除:被降级主机始终保留在负载均衡轮换中,max_ejection_percent不约束它;真正被隔离的主机走剔除路径。
  3. 退避参数复用:降级时长复用base_ejection_time/max_ejection_time/max_ejection_time_jitter/interval,调这些参数会同时影响剔除与降级行为。
  4. 流量是渐进溢出的:由第 2 节表格可知,降级主机只在健康占比不足以承载 100% 负载时逐步承接流量,与优先级溢出机制同源,因此它与 优先级、panic 阈值 等机制组合生效。
  5. 版本前提detect_degraded_hosts字段(字段号 26)及相关实现为较新版本引入(见 1.38.0 changelog),在旧版本集群配置中该字段不存在;主动健康检查的x-envoy-degraded头则是较早已有的能力。
  6. 上游侧契约:上游服务需在“资源紧张但仍可服务”的语义下自行返回x-envoy-degraded头(例如容量水位超阈值),Envoy 只负责消费该信号,不做阈值判定。

7. 小结

Envoy 的降级端点机制在上游主机状态谱系中补上了关键一环:既不“一刀切”地把亚健康主机踢出集群(剔除),也不放任其与健康主机均分流量,而是通过优先级溢出的同源机制让流量随健康占比的下降渐进式转移。实现上,该能力以DEGRADED_OUTLIER_DETECTION健康标志为载体,由 outlier_detection_impl.cc 中的置位/退避/清除三阶段闭环驱动,并通过 admin 健康状态、membership_degraded统计与DEGRADED类型事件日志提供完整的可观测链路。对于需要在缩容、金丝雀或容量受限时保留“可降级服务能力”的集群,正确配置detect_degraded_hosts并让上游规范返回x-envoy-degraded头,是落地该机制的两个必要前提。

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询