架构与配置实战:资源监控、触发器与过载动作的完整解析)
Envoy 过载管理器Overload Manager架构与配置实战资源监控、触发器与过载动作的完整解析【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoyEnvoy 的 Overload Manager 是一个可扩展的自保护组件用于在连接数或请求量激增时防止代理进程因内存、CPU、文件描述符等系统资源耗尽而崩溃。本文基于 Envoy 仓库中的架构文档与配置文档完整讲解其“资源Resources→ 触发器Triggers→ 动作Actions”三层模型、全部内置资源监控器、过载动作与负载卸载点Load Shed Points的配置方法并结合source/server/overload_manager_impl.cc等源码剖析触发器状态机、线程本地状态分发与概率式负载卸载的实现细节。一、定位保护 Envoy 自身而非保护上游过载管理器保护的对象是Envoy 服务器本身。文档明确指出它与熔断机制Circuit Breaking 的目标不同——熔断主要是保护上游服务不被打垮而过载管理器是当“过多的客户端连接或请求”压垮各种系统资源内存、CPU、文件描述符等时保护 Envoy 进程自身不被压垮。这一点在工程实践上意味着过载管理器是边缘/入口侧的最后一道防线。配合 K8s、裸金属部署时它可以避免单个 Envoy 实例 OOM 或被宿主机 CPU 打满从而防止整个机队fleet进入级联故障cascading failure模式。配置入口位于 Bootstrap 的overload_manager字段中即 envoy/config/bootstrap/v3/bootstrap.proto 中的overload_manager。二、总体架构Resources → Triggers → Actions过载管理器的工作方式是周期性地轮询一组资源的“压力pressure”将压力值送入触发器进行求值再根据触发结果执行动作。资源监控器、触发器和动作这三类组件都在启动时startup指定不可动态增删。2.1 Resources资源资源是能被过载管理器监控的对象其压力用[0, 1]区间内的实数表示。压力由一个**资源监控器resource monitor**计算得出。Envoy 使用统一的扩展Extension框架 定义资源监控器内置的监控器包括监控器名称作用源码位置envoy.resource_monitors.fixed_heap以固定堆上限为分母衡量进程堆内存使用率fixed_heap 监控器envoy.resource_monitors.cgroup_memory读取 cgroupv1/v2内存用量与限额报告“当前用量/内存限额”比值cgroup_memory 监控器envoy.resource_monitors.cpu_utilization主机或容器 CPU 利用率监控cpu_utilization 监控器envoy.resource_monitors.global_downstream_max_connections全局下游活跃连接数监控downstream_connections 监控器envoy.resource_monitors.injected_resource测试/外部注入资源用于模拟压力injected_resource 监控器2.2 Triggers触发器触发器在每次资源压力更新时被重新求值把压力值转换成动作状态action state。动作状态同样是[0, 1]的值并分为两类动作状态取值含义scaling[0, 1)资源压力低于配置的饱和点可以开始执行渐进式动作saturated1资源压力达到或超过配置的饱和点应当执行强烈drastic动作当某个资源的压力值更新时相关的触发器重新求值。对于配置了至少一个触发器的每个动作其最终动作状态是所有触发器状态的最大值max over triggers。动作状态具体产生什么效果取决于动作的配置与实现。2.3 Actions动作当触发器状态变化时新状态被分发给注册过该动作的组件这些组件随后可以改变连接与请求的处理方式。每个动作对输入状态的解读方式不同有些动作会完全忽略scaling状态只在saturated时生效。一个重要的联动行为当 HttpConnectionManager.append_local_overload 被设为true时过载导致的 HTTP 请求丢弃会在连接管理器发出的本地应答local reply中携带 x-envoy-local-overloaded 响应头便于客户端感知本次失败是由 Envoy 过载而非上游故障引起的。三、完整配置示例三级阈值保护下面是一个完整的 Overload Manager 配置来自配置文档。它的语义是堆内存达到 92% 时排水 HTTP/1/2/3 连接达到 95% 时对新请求返回 503达到 95% 时停止接受新 TCP 连接refresh_interval: seconds: 0 nanos: 250000000 resource_monitors: - name: envoy.resource_monitors.fixed_heap typed_config: type: type.googleapis.com/envoy.extensions.resource_monitors.fixed_heap.v3.FixedHeapConfig max_heap_size_bytes: 2147483648 actions: - name: envoy.overload_actions.disable_http_keepalive triggers: - name: envoy.resource_monitors.fixed_heap threshold: value: 0.92 - name: envoy.overload_actions.stop_accepting_requests triggers: - name: envoy.resource_monitors.fixed_heap threshold: value: 0.95 loadshed_points: - name: envoy.load_shed_points.tcp_listener_accept triggers: - name: envoy.resource_monitors.fixed_heap threshold: value: 0.95其中refresh_interval是资源轮询周期本例为 0.25 秒。从源码看若未配置该字段OverloadManagerImpl 构造函数 通过PROTOBUF_GET_MS_OR_DEFAULT(config, refresh_interval, 1000)将其默认为 1000 毫秒。四、Cgroup Memory 监控器K8s 环境下的内存压力度量envoy.resource_monitors.cgroup_memory通过读取 cgroup 内存子系统的用量与限额来跟踪内存压力同时支持 cgroup v1 和 v2。它把压力报告为“当前用量 / 内存限额”的比值。限额的确定规则是优先使用 cgroup 报告的内存限额典型场景若配置了max_memory_bytes则取“配置的max_memory_bytes”与“cgroup 限额”的较小值作为压力计算的分母即max_memory_bytes充当分母上限当 cgroup 未设置内存限额v1 中为-1、v2 中为max时压力报告为 0。示例配置resource_monitors: - name: envoy.resource_monitors.cgroup_memory typed_config: type: type.googleapis.com/envoy.extensions.resource_monitors.cgroup_memory.v3.CgroupMemoryConfig max_memory_bytes: 1073741824 # 1GB配合动作即可在内存压力升高时卸载负载actions: - name: envoy.overload_actions.stop_accepting_requests triggers: - name: envoy.resource_monitors.cgroup_memory threshold: value: 0.95 # Trigger at 95% memory utilization五、触发器详解threshold 与 scaled触发器把资源监控器连接到动作支持两种类型类型行为threshold资源压力高于阈值时动作状态置 1saturated否则置 0scaled压力低于scaling_threshold时状态为 0处于scaling_threshold pressure saturation_threshold之间时状态为(pressure - scaling_threshold) / (saturation_threshold - scaling_threshold)压力达到或超过saturation_threshold时状态为 1saturated源码中两个触发器的实现清晰印证了上述语义ThresholdTriggerImplupdateValue()中直接比较value threshold_状态只在 saturated 与 inactive 之间切换ScaledTriggerImpl构造时强制校验scaling_threshold saturation_threshold否则返回InvalidArgumentErrorupdateValue()按三段式计算状态值。而“动作状态取所有触发器最大值”的规则在 OverloadAction::updateResourcePressure 中实现每次某个触发器更新后遍历triggers_取最大值写入state_并同步刷新active/scale_percent两个统计量。六、内置过载动作全表动作名称行为envoy.overload_actions.stop_accepting_requests对新请求立即返回 503envoy.overload_actions.disable_http_keepalive用带排水宽限期的GOAWAY排水 HTTP/2 和 HTTP/3 连接对 HTTP/1 则启动排水定时器关闭更久未使用的空闲连接envoy.overload_actions.stop_accepting_connections停止在配置的 listener 上接受新的网络连接envoy.overload_actions.reject_incoming_connections在配置的 listener 上直接拒绝入站连接不处理任何数据envoy.overload_actions.shrink_heap周期性尝试收缩堆把空闲内存归还给操作系统envoy.overload_actions.reduce_timeouts降低一组超时时间的等待时长见下文envoy.overload_actions.reset_high_memory_stream重置终止占用内存较高的流见下文envoy.overload_actions.close_idle_http_connections动作激活时关闭空闲的下游 HTTP/3 QUIC 连接saturated时激进关闭忽略空闲定时器阈值scaled状态下仍尊重空闲定时器阈值。目前仅支持 HTTP/3 QUIC6.1 shrink_heap定期归还空闲内存envoy.overload_actions.shrink_heap在被触发后会周期性尝试把堆上空闲内存归还给操作系统对减少内存碎片、在使用 tcmalloc 时尤其有用。它可通过ShrinkHeapConfig配置参数默认值说明timer_interval10s检查是否应释放内存的间隔max_unfreed_memory_bytes104857600100MB归还给系统前允许保留的最大未释放内存量来自仓库示例文件 shrink_heap_overload.yaml 的配置片段actions: - name: envoy.overload_actions.shrink_heap typed_config: type: type.googleapis.com/envoy.config.overload.v3.ShrinkHeapConfig timer_interval: 5s max_unfreed_memory_bytes: 52428800 triggers: - name: envoy.resource_monitors.fixed_heap threshold: value: 0.9若不提供typed_config动作使用默认值。源码侧OverloadManagerImpl构造时若识别到ShrinkHeap动作且带有typed_config会通过anyConvertAndValidate解析出ShrinkHeapConfig缓存下来见 overload_manager_impl.cc#L525-L530并在接口上以getShrinkHeapConfig()暴露给堆收缩器使用实际的收缩逻辑位于 heap_shrinker.cc。6.2 reduce_timeouts按压力缩放超时时间envoy.overload_actions.reduce_timeouts在资源压力升高时缩短 Envoy 等待各类交互完成的超时时长。每类超时的最小值可以配置为“对配置最大值应用一个缩放因子”或一个具体时长。示例单个动作条目name: envoy.overload_actions.reduce_timeouts triggers: - name: envoy.resource_monitors.fixed_heap scaled: scaling_threshold: 0.85 saturation_threshold: 0.95 typed_config: type: type.googleapis.com/envoy.config.overload.v3.ScaleTimersOverloadActionConfig timer_scale_factors: - timer: HTTP_DOWNSTREAM_CONNECTION_IDLE min_timeout: 2s该配置让 HTTP 连接的空闲超时随堆使用率变化堆用量低于 85% 时按 idle_timeout 原值超时达到或超过 95% 时空闲连接在min_timeout2 秒后被关闭介于 85% 与 95% 之间时按 scaled trigger 的线性公式在两者之间插值。例如RouteAction.idle_timeout 600s、堆用量 92% 时空闲超时为2s (600s - 2s) × (95% − 92%) / (95% − 85%) 181.4s。若把min_timeout: 2s换成min_scale: { value: 10 }则最小超时值改为基于最大值计算idle_timeout 600s时最小值为10% × 600s 60s。从源码看reduce_timeouts是少数支持typed_config的动作之一构造期解析timer_scale_factors得到 ScaledTimerTypeMap其中min_timeout与min_scale二选一min_scale按value / 100.0换算重复配置同一 timer 类型会直接报InvalidArgumentError。这些最小值随后经scaledTimerFactory()注入到各超时计时器实现“压力越大、超时越短”的动态缩放。6.3 reset_high_memory_stream按内存分桶重置流注意通过过载动作重置流目前仅对 HTTP/2 生效文档中的显式警告。envoy.overload_actions.reset_high_memory_stream会重置“昂贵”的流。它必须通过 OverloadManager 的buffer_factory_config配置minimum_account_to_track_power_of_twobuffer_factory_config: minimum_account_to_track_power_of_two: 20 actions: name: envoy.overload_actions.reset_high_memory_stream triggers: - name: envoy.resource_monitors.fixed_heap scaled: scaling_threshold: 0.85 saturation_threshold: 0.95只有使用 ≥2^minimum_account_to_track_power_of_two缓冲内存的流才会被跟踪。上例中2^20 1MiB即跟踪缓冲占用 ≥ 1MiB 的流并按 8 个 2 的幂大小的桶分类桶数当前硬编码为 8桶索引包含的流缓冲占用0[1MiB, 2MiB)1[2MiB, 4MiB)2[4MiB, 8MiB)3[8MiB, 16MiB)4[16MiB, 32MiB)5[32MiB, 64MiB)6[64MiB, 128MiB)7≥ 128MiB重置策略按堆用量分档推进堆用量低于 85% 时不重置任何流达到 85% 开始重置最后一个桶≥128MiB的流在85% 1 × gradation处扩展到后两个桶≥64MiB其中gradation (saturation_threshold − scaling_threshold) / 8到达 95% 时所有 ≥1MiB 的流都有资格被重置。每次动作触发时每个 worker 最多重置 50 个流硬编码上限既减少被重置的流数量也避免 worker 线程长时间停摆触发 Watchdog。由于只有 8 个桶前几档梯度通常不应触发重置——除非真的存在 ≥128MiB 缓冲的异常流。源码中ResetStreams动作在构造 OverloadManagerImpl 时强制校验buffer_factory_config存在否则直接拒绝启动见 overload_manager_impl.cc#L518-L524并注册ResetStreamsCount计数器。七、Load Shed Points连接/流生命周期上的卸载决策点Load Shed Points与过载动作类似都由触发器驱动但决定的是 Envoy 在连接或流生命周期的某个关键点是否“卸掉”这段负载。可以把已配置的卸载点理解为一棵决策树新连接上的请求会在生命周期的各个枢纽junction依次过检——即使它通过了前一个枢纽条件变化后仍可能在更后面的枢纽被卸载。与过载动作相比Load Shed Points 的特点对条件变化更敏感尤其适合大流量突刺场景过载动作更适合“Envoy 想卸负载、但 worker 线程并没有在主动处理对应连接/流”的情况例如reset_high_memory_stream可以重置并不在推进的高内存流更易于集成自定义扩展只要扩展能访问 Overload Manager就可以注册公司内部company internal的自定义卸载点。核心卸载点列表名称行为envoy.load_shed_points.tcp_listener_accept在Listener Filter Chain 创建之前拒绝关闭新 TCP 连接envoy.load_shed_points.http_connection_manager_decode_headersHTTP 编解码器解析完头部、HTTP Filter Chain 实例化之前用本地应答拒绝新 HTTP 流envoy.load_shed_points.http1_server_abort_dispatch在编解码层拒绝处理 HTTP/1若响应尚未开始发送本地应答然后关闭连接envoy.load_shed_points.http2_server_go_away_on_dispatch在编解码层处理 HTTP/2 请求时发送GOAWAY最终排水该 HTTP/2 连接envoy.load_shed_points.hcm_ondata_creating_codec在收到数据、准备创建 codec 之前关闭连接通常因内存压力envoy.load_shed_points.http_downstream_filter_check在路由创建上游请求前直接发送本地应答使负载卸载检查在 HTTP 解码器过滤器中可用envoy.load_shed_points.connection_pool_new_connection压力下连接池停止创建新连接若该点拒绝了新连接且无可用容量下游请求将失败envoy.load_shed_points.http2_server_go_away_and_close_on_dispatch发送GOAWAY并立即强制关闭下游连接。若同时配置了http2_server_go_away_on_dispatch且两者都应卸载本点优先。这是破坏性动作下游非优雅断开只应在极高阈值甚至不使用envoy.load_shed_points.tcp_proxy_on_dataTCP 代理过滤器在收到数据如早期数据缓冲或代理过程中时若资源压力高则关闭下游 TCP 连接源码层面LoadShedPointImpl 的shouldShedLoad()实现揭示了一个关键细节卸载是概率式的而非全有或全无。每个卸载点维护一个原子变量probability_shed_load_其值取所有触发器状态的最大值当概率为 1.0 时必然卸载否则通过random_generator_.bernoulli(probability)做伯努利抽样决定本次是否卸载并在命中时递增shed_load_count计数器。这意味着在scaling未饱和阶段Envoy 按压力比例“随机丢弃”一部分请求——这正是配置文档所说的“对大流量突刺更敏感”的实现基础也让压力曲线与卸载强度呈平滑的线性关系。八、限制全局活跃下游连接数要限制所有 listener 上的活跃下游连接总数在 Overload Manager 中配置全局下游连接监控器resource_monitors: - name: envoy.resource_monitors.global_downstream_max_connections typed_config: type: type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig max_active_downstream_connections: 1000要点均出自配置文档max_active_downstream_connections不支持 runtime 更新。也可通过 runtime keyoverload.global_downstream_max_connections设置整数值但该 key 已废弃将在未来移除建议连接上限小于系统文件描述符限额的一半为上游连接、文件和其他 fd 用途留出余量若未指定该值全局连接数无上限Envoy 启动时会打印警告若不想设置上限又想消除警告可把该值设得极大约 2×10⁹Listener 可通过 Listener.ignore_global_conn_limit 设为true退出该全局限制Admin listener 同样可用 Admin.ignore_global_conn_limit 退出。退出限制的 listener 仍可用来探测 Envoy 或采集统计例如其他 listener 已达连接上限时。注意退出限制的 listener 的连接仍会被跟踪并计入全局限额若只想限制某个特定 listener可用listener 配置中的 per-listener 限额per-listener 与全局限额可同时指定且各自独立生效。仓库中的边缘最佳实践配置 edge best practices 给出了完整组合示例其示例文件为 edge.yaml。九、CPU 密集型负载的 Brownout 保护envoy.overload_actions.stop_accepting_requests配合envoy.resource_monitors.cpu_utilization监控器可在请求量意外激增导致 CPU 饱和时通过低成本的拒绝新请求来保护负载不被“棕化”brown-out。真正的根治手段是水平扩容但过载动作能确保整个机队不会因此进入级联故障模式。部分平台方会默认安装该动作来保护机队因为配置“目标 CPU 利用率百分比”比为每个负载配置“请求速率”更容易。CPU 监控器支持两种模式mode: HOST默认主机 CPU 利用率与mode: CONTAINERK8s 容器 CPU 利用率。HOST 模式示例取自 cpu_utilization_monitor_overload.yamloverload_manager: refresh_interval: 0.25s resource_monitors: - name: envoy.resource_monitors.cpu_utilization typed_config: type: type.googleapis.com/envoy.extensions.resource_monitors.cpu_utilization.v3.CpuUtilizationConfig actions: - name: envoy.overload_actions.stop_accepting_requests triggers: - name: envoy.resource_monitors.cpu_utilization scaled: scaling_threshold: 0.80 saturation_threshold: 0.95这里采用scaled触发器CPU 利用率低于 80% 时不拒绝80%–95% 之间按压力比例渐进拒绝概率式 503≥95% 时全部拒绝。K8s 环境下的负载卸载在 Kubernetes 中Envoy 工作负载常与其他应用共享节点资源。与其定义固定请求速率不如用“目标容器 CPU 利用率百分比”这种更灵活的度量——Envoy 可基于容器级指标动态管理 CPU 使用而不影响同节点的其他负载。将监控器设为mode: CONTAINER即可取自 container_cpu_utilization_monitor_overload.yamloverload_manager: refresh_interval: 5s resource_monitors: - name: envoy.resource_monitors.cpu_utilization typed_config: type: type.googleapis.com/envoy.extensions.resource_monitors.cpu_utilization.v3.CpuUtilizationConfig mode: CONTAINER actions: - name: envoy.overload_actions.stop_accepting_requests triggers: - name: envoy.resource_monitors.cpu_utilization scaled: scaling_threshold: 0.80 saturation_threshold: 0.95十、统计指标观测过载管理器的运行状态每个已配置的资源监控器都有一棵以overload.name.为根的统计树指标类型说明pressureGauge资源压力百分比failed_updatesCounter更新资源压力失败的总次数skipped_updatesCounter因已有更新排队而跳过的更新次数refresh_interval_delayHistogram资源刷新循环之间的延迟每个已配置的过载动作的统计树同样以overload.name.为根指标类型说明activeGauge动作激活状态0scaling1saturatedscale_percentGauge动作的缩放值0–99scaling100saturated每个已配置 Load Shed Point 的统计树也以overload.name.为根指标类型说明scale_percentGauge缩放值0–99scaling100saturatedshed_load_countCounter累计卸载shed次数这些指标正是源码中makeGauge/makeCounter构造的overload. .active 等统计。运维上可以基于pressure与active/scale_percent搭建告警用shed_load_count评估触发频率是否与容量规划匹配。十一、源码结构深潜主循环、线程本地分发与符号表结合 source/server/overload_manager_impl.h 与实现文件可以梳理出过载管理器的运行时骨架轮询主循环OverloadManagerImpl持有refresh_interval_默认 1s与一个Event::TimerPtr timer_周期性刷新各资源监控器每次刷新前后通过time_resources_last_measured_计算间隔并写入refresh_interval_delay直方图。资源更新采用“刷新纪元flush epoch”批量语义——Resource内部有pending_update_标志同一纪元内重复更新会被合并对应skipped_updates计数更新最终经flushResourceUpdates()一次性分发给所有动作回调。动作状态的跨线程分发动作回调可能注册在任意 worker 线程的 dispatcher 上。OverloadManagerImpl将各动作状态打包进state_updates_to_flush_/callbacks_to_flush_再通过 ThreadLocalThreadLocalOverloadStateImpl投递到每个 worker 线程保证状态检查无锁、低开销。符号表加速热路径NamedOverloadActionSymbolTable 把动作名字符串映射为从 0 开始顺序编号的符号索引worker 线程读取状态时按索引取actions_向量避免热路径上的字符串哈希。启动期严格校验动作名必须是已知动作Unknown Overload Manager Action、资源名必须已配置Unknown trigger resource、动作/监控器不可重名、reduce_timeouts之外的动作不允许携带typed_configshrink_heap除外。这些校验全部发生在 OverloadManagerImpl 构造阶段配置错误会在启动时直接暴露而非运行期。主动式资源proactive resources除被轮询的资源外管理器还维护一组“主动式资源”——它们不参与周期性刷新而是由扩展在分配/释放内存等时机按需调用tryAllocateResource/tryDeallocateResource即时更新压力见 ThreadLocalOverloadStateImpl典型用于按 buffer 用量精细跟踪高内存流这正是reset_high_memory_stream能区分各桶的基础。十二、配置建议小结阈值分级先用disable_http_keepalive较低阈值排水连接释放资源再用stop_accepting_requests较高阈值拒绝新请求最后才动用 Load Shed Points 的强断开手段如http2_server_go_away_and_close_on_dispatch优先 scaled 触发器对 CPU/内存这类连续压力指标scaled 触发器配合概率式卸载与超时缩放能形成平滑的降级曲线比 threshold 的“悬崖式”切换对上游更友好K8s 场景容器化部署优先用cgroup_memory或cpu_utilization(mode: CONTAINER)监控器避免按主机指标误判同节点其他负载的资源占用可观测先行上线前确认overload.*统计已接入监控系统用shed_load_count与active验证触发行为符合预期谨慎使用破坏性动作强制关闭类卸载点和reset_high_memory_stream都会直接中断在途流量应设置很高的饱和阈值并先在灰度环境验证。综上Envoy 过载管理器以“资源监控器 → 触发器 → 动作/卸载点”的三层可插拔模型把“保护代理自身”从依赖运维经验的手工限流变成了可声明、可观测、概率式平滑降级的内建能力理解其 threshold/scaled 两种触发语义与 Load Shed Points 的概率卸载实现是把它用对、用好的前提。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考