Envoy Load-Aware Locality 负载均衡策略:基于 ORCA 利用率余量的 locality 感知路由
2026/9/12 16:09:05 网站建设 项目流程

Envoy Load-Aware Locality 负载均衡策略:基于 ORCA 利用率余量的 locality 感知路由

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

导读

Envoy 在负载均衡领域引入了envoy.load_balancing_policies.load_aware_locality(Load-Aware Locality-Picking)负载均衡策略:它不再依赖静态的 locality 权重配置,而是通过 ORCA(Open Request Cost Aggregation)上报的利用率数据计算每个 locality 的可用余量(headroom),据此在多个 zone/region 之间动态分配流量,并且适用于所有 priority 级别。读完本文,你将掌握该策略的配置字段与默认值、基于 ORCA 利用率的权重计算与 EWMA 平滑原理、本地优先与远端探测机制,以及当前实现的适用边界(官方标注为 work-in-progress,不建议生产使用)。

该策略在 changelog 中登记为:load_balancing: implemented the envoy.load_balancing_policies.load_aware_locality locality-picking load balancer(见 changelogs/current/new_features/load_balancing__load-aware-locality-lb-policy.rst),属于"new features"列表中的一项新增能力。

一、策略定位:从"按配置权重"到"按利用率余量"

传统的 zone-aware 负载均衡依赖管理员为每个 locality 配置静态权重或依靠调度器下发权重;而 Load-Aware Locality 的思路是:

  • 数据来源:消费 ORCA 上报的负载报告(默认走逐请求的 in-band 上报,也可开启 out-of-band 上报);
  • 核心指标:以 ORCA 推导出的利用率(utilization)为基准,计算每个 locality 的"剩余容量"(headroom,即1 - utilization);
  • 决策粒度:先按利用率余量为 locality 分配权重,选定 locality 之后再交给内部的 child LB 策略在 host 级别做端点选择;
  • 适用范围:在所有 priority 级别(all priority levels)上都生效,而非仅作用于最高优先级。

从扩展注册信息看,该策略在 source/extensions/extensions_metadata.yaml 中以envoy.load_balancing_policies.load_aware_locality名称注册,对应的 proto 消息为envoy.extensions.load_balancing_policies.load_aware_locality.v3.LoadAwareLocality。需要特别强调的是,changelog 与本仓库源码均明确标注该扩展为work-in-progress 且不用于生产环境("The extension is work-in-progress and not intended for production use"),读者在选型时应留意这一前提。

二、配置详解:proto 字段、默认值与校验规则

策略配置定义在 api/envoy/extensions/load_balancing_policies/load_aware_locality/v3/load_aware_locality.proto,共 9 个可配置字段。下面是完整字段表:

字段类型默认值校验规则说明
endpoint_picking_policyconfig.cluster.v3.LoadBalancingPolicy无(必填)required每个 locality 内部做端点选择的 child LB 策略
weight_update_periodgoogle.protobuf.Duration1s至少 100ms主线程上重算 ORCA 权重与 locality 利用率的周期
metric_names_for_computing_utilizationrepeated string用于计算端点利用率的 ORCA 指标名列表
utilization_variance_thresholdgoogle.protobuf.DoubleValue0.1[0, 1]本地利用率相对远端平均值低于该阈值时,100% 流量留在本地
smoothing_time_constantgoogle.protobuf.Duration5s> 0slocality 利用率 EWMA 平滑时间常数
remote_probe_fractiongoogle.protobuf.DoubleValue0.03[0, 1)为保证 ORCA 数据新鲜度而分给远端 locality 的最小流量比例
weight_expiration_periodgoogle.protobuf.Duration3 分钟≥ 0s单 host ORCA 样本的有效窗口,0s 表示不失效
enable_oob_load_reportgoogle.protobuf.BoolValuefalse是否开启端点的 out-of-band 利用率上报(默认逐请求上报)
oob_reporting_periodgoogle.protobuf.Duration10s请求服务端上报的间隔,仅当enable_oob_load_report为 true 时生效

以上默认值与校验规则并非仅存在于 proto 注释中——config.cc 的Factory::loadConfig逐项落实了这些约束:weight_update_period不足 100ms 时报InvalidArgumentError("weight_update_period must be at least 100ms")smoothing_time_constant必须为正,utilization_variance_threshold必须在 [0,1] 区间,remote_probe_fraction必须在 [0,1)。对应测试 config_test.cc 中的LoadAwareLocalityConfigTest.Defaults也验证了默认值:weightUpdatePeriod() == 1000msutilizationVarianceThreshold() == 0.1remoteProbeFraction() == 0.03weightExpirationPeriod() == 180000ms

2.1 关键字段的语义细节

metric_names_for_computing_utilization(利用率来源):对于 ORCA proto 中的 map 类型字段,字符串形如<map_field_name>.<map_key>,例如named_metrics.foo表示取 ORCAnamed_metrics字段中 key 为foo的值。利用率的取值优先级为:先取本列表指定指标中大于 0 的最大值;若都不大于 0,则回退到application_utilization;再回退到cpu_utilization。此外还存在一个运行时开关envoy.reloadable_features.orca_weight_manager_use_named_metrics_first(见 source/common/runtime/runtime_features.cc 中的RUNTIME_GUARD声明):禁用该开关可恢复旧优先级顺序,即优先使用application_utilization而非 named metrics。

utilization_variance_threshold(本地偏好阈值):当本地 locality 的利用率"至多"比远端平均利用率高该阈值时,100% 的流量路由到本地,从而避免在负载基本均衡时产生不必要的跨 zone 流量。该判断是单向的:若本地 zone 负载低于远端,则始终全本地路由。实现位于computeSourceWeights:当utilizations[0] <= target_util + utilization_variance_threshold_时置local_preferred并将全部权重收敛到本地。

smoothing_time_constant(EWMA 平滑):每个 tick 的平滑因子alpha = 1 - exp(-weight_update_period / smoothing_time_constant)。由于 alpha 由 tick 周期与时间常数共同推导,无论配置多快的更新周期,settling 时间保持一致:默认 5s 常数下约 95% 在约 15s 内收敛。更大的值权重更稳定、反应更慢;更小的值反应更快。该推导在 config.cc 中实现:ewma_alpha = 1.0 - std::exp(-weight_update_period / smoothing_time_constant)

remote_probe_fraction(远端探测流量):当本地偏好判断会导致 100% 流量留在本地时,为保证 ORCA 数据不陈旧,需要保留一小部分流量打到远端 locality。该比例是全局值,会按 host 数量比例拆分到所有远端 locality;注意"探针比例是全局值,分摊到所有远端 locality"——在远端 locality 数量非常多且总请求率很低时,单个 host 的采样间隔可能超过weight_expiration_period(proto 注释提到架构总览中给出了扩展性矩阵)。设为 0 可关闭,但仅当 ORCA 报告以 out-of-band 方式到达、或必须严格避免跨 zone 流量时才安全。

weight_expiration_period(样本有效期):host 在该时长内没有上报负载指标,则被排除出其 locality 的利用率聚合。locality 的 EWMA 状态会在剩余上报 host 上继续正常演进。若某个 locality 的全部 host 都过期,该 locality 回退到按 host 数量成比例的权重(与所有 locality 过载时的路径相同)。设为 0s 关闭过期机制。

三、完整的 YAML 配置示例

下面是在 cluster 上启用该策略的最小可运行配置(children 使用 round_robin 作为 locality 内部端点选择器):

load_balancing_policy: policies: - typed_extension_config: name: envoy.load_balancing_policies.load_aware_locality typed_config: "@type": type.googleapis.com/envoy.extensions.load_balancing_policies.load_aware_locality.v3.LoadAwareLocality endpoint_picking_policy: policies: - typed_extension_config: name: envoy.load_balancing_policies.round_robin typed_config: "@type": type.googleapis.com/envoy.extensions.load_balancing_policies.round_robin.v3.RoundRobin weight_update_period: 1s utilization_variance_threshold: 0.1 smoothing_time_constant: 5s remote_probe_fraction: 0.03 weight_expiration_period: 180s metric_names_for_computing_utilization: - named_metrics.foo # enable_oob_load_report: true # oob_reporting_period: 10s

在 integration_test.cc 的集成测试中可以看到该策略的完整装配方式:测试将 node 的 locality 设置为region=test-region, zone=zone-a,在load_assignment下同时配置本地 zone(zone-a)与远端 zone(zone-b)的 locality 分组,再通过load_balancing_policy挂载上述策略,从而验证跨 zone 场景下的路由行为。这也提示了一个部署前提:该策略依赖端点配置中 locality 分组信息(load_assignment.endpoints[].locality),本地 locality 由 Envoy 自身所在 zone 判定。

四、实现原理:主线程算权重,Worker 线程选端点

从源码结构看,该扩展的实现是典型的主线程/工作线程分工模型,核心类位于 load_aware_locality_lb.h 与 load_aware_locality_lb.cc:

  • 主线程LoadAwareLocalityLoadBalancer(实现ThreadAwareLoadBalancer)通过定时器周期性地执行computeLocalityRoutingWeights(),把所有 priority、所有 SelectionSource(Healthy / Degraded / AllHosts)下的 locality 权重算好后,以RoutingWeightsSnapshot快照形式通过 TLS(ThreadLocalShim)发布到各 worker;
  • Worker 线程WorkerLocalLb(继承LoadBalancerBase)维护每个 locality 的 child LB(PerLocalityState),每次选路时先做 live 的 priority/健康度选择(resolvePrioritySource),再按发布的权重快照选择 locality(chooseLocality),最后把请求委托给该 locality 的 child LB 完成端点选择(chooseHost)。

4.1 权重计算:host 数 × (1 - utilization)

computeSourceWeights是权重计算的核心(load_aware_locality_lb.cc):

  1. 对每个 locality,遍历其健康/降级/全部 host,读取每个 host 的 ORCA 利用率,过滤掉从未上报(kNeverReported)或已超过weight_expiration_period的过期 host,求平均得到avg_utils[i]
  2. 用 EWMA 平滑:smoothed = alpha * avg_utils[i] + (1 - alpha) * prev,平滑后的利用率存入LocalityEwmaMap(以 locality 身份为 key,避免 host 增删导致的下标错位);
  3. 计算基础权重:weight = host_count * max(0.0, 1.0 - utilization)——即利用率余量(headroom)越大、host 越多,权重越高;无有效样本(stale)的 locality 直接退化为host_count
  4. 三种退化/修正路径:
    • 全过载(all_overloaded):若总基础权重为 0 且存在 host,回退为按 host 数量成比例分配;
    • 本地偏好(local_preferred):本地利用率 ≤ 远端加权平均利用率 + 阈值时,全部权重收敛到本地(all_local);
    • 远端探测(probe_active):若远端权重占比低于remote_probe_fraction,从本地权重中切出一部分,按远端 host 数量比例重新分配。

4.2 ORCA 上报数据的消费与新鲜度

每个 host 的负载数据存放在LocalityLbHostData(实现HostLbPolicyData)中:worker 线程调用onOrcaLoadReport写入利用率,主线程读取。跨线程写入通过std::atomic<double>std::atomic<MonotonicTime>完成,代码中有static_assert保证两个原子类型都是无锁的(lock-free)。值得注意的是:无利用率信号(util <= 0.0)的报告不会刷新 freshness 时间戳,从而让静默 host 自然过期而不是"钉住"空闲状态。

底层 ORCA 处理复用能力来自 source/extensions/load_balancing_policies/common/orca_weight_manager.h:OrcaLoadReportHandler::getUtilizationFromOrcaReport()负责从xds.data.orca.v3.OrcaLoadReport中按metric_names_for_computing_utilization提取利用率;OrcaWeightManager原本从 ClientSideWeightedRoundRobin 中抽取、供多个 LB 策略复用。本策略的 host 数据仅存利用率与时间戳(不做 QPS/EPS 加权),这是它与 client_side_weighted_round_robin 的差异点。

4.3 每次选路:一次随机、两步决策

Worker 端每次选路只消耗一次随机数(resolvePrioritySourcerandom(peeking)),priority/健康度选择与 locality 选择共享该随机数:locality 目标通过splitMix64(hash)二次派生(黄金比例递增 + 收尾混合),使两个决策相互独立。权重快照在发布时即被转换为按 locality 下标的前缀和数组refreshLocalityWeights),选路时用std::upper_bound二分查找完成,避免逐次哈希 locality 身份;快照与拓扑不一致时(如 child LB 因 host 变更被拆除),pickLocalityLb会从下一个下标开始环绕扫描可用的 child LB,避免并发 drain 全部压到同一个 locality。

4.4 可观测性:专用计数器

主线程每次重算都会更新以下计数器(定义于 load_aware_locality_lb.h),统计名前缀为load_aware_locality

计数器语义
recompute_total权重重算总次数
all_overloaded_total出现全过载回退的 tick 数
local_preferred_total触发本地偏好(全本地路由)的 tick 数
probe_active_total远端探测流量生效的 tick 数
spill_active_total本地负载过高、向外溢出的 tick 数
stale_locality_total累计的陈旧 locality 计数

此外 Worker 端复用标准 zone 路由统计(lb_zone_routing_cross_zonelb_zone_routing_all_directlylb_zone_routing_sampled)来区分跨 zone、全直达与被采样的路由(见recordZoneRoutingStats)。

五、边界条件与适用前提

  • 官方状态:该扩展为 work-in-progress,changelog 与代码注释均明确不用于生产环境,评估与选型时请以这一状态为准;
  • 配置校验细节endpoint_picking_policy是必填项,且不允许嵌套自身(load_aware_locality cannot be its own endpoint_picking_policy,避免统计重复注册与 metric 丢失);若无法实例化 child 策略,集群初始化会失败(Unsupported endpoint picking policy for load_aware_locality: ...),从而不会进入 worker 阶段(见 config.cc 与 load_aware_locality_lb.cc);
  • 数据新鲜度与探针比例的权衡:默认 3% 的远端探针流量是全局值,跨 zone 流量被严格禁止的部署需要显式置 0(仅当 ORCA 走 out-of-band 上报时安全);远端 locality 数量多而请求量低时,需参照weight_expiration_period与采样矩阵调整参数;
  • 依赖 ORCA 上报链路:默认逐请求(in-band)上报,要求端点侧能够随 RPC 响应携带 ORCA 负载报告;如需降低 per-request 开销,可开启enable_oob_load_report并配合oob_reporting_period(服务端实际上报频率可能低于请求值)。

六、结语

envoy.load_balancing_policies.load_aware_locality是 Envoy 在 locality 级负载均衡上的一次新尝试:它把 ORCA 利用率数据、EWMA 平滑、本地偏好阈值与远端探测机制组合成一套"按剩余容量路由"的 locality 选择策略,并在所有 priority 级别生效。其主线程计算/Worker 执行的架构、基于前缀和与二分查找的选路路径、以及完善的统计埋点,为后续在生产环境打磨提供了清晰的实现基础。读者可结合 api 侧 proto 定义、主实现 以及 config 测试、集成测试 继续深入验证其行为。

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

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

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

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

立即咨询