Envoy 自适应并发控制新特性:min_concurrency_limit 与 minRTT 测量并发解耦实战指南
2026/9/12 18:11:32 网站建设 项目流程

Envoy 自适应并发控制新特性:min_concurrency_limit 与 minRTT 测量并发解耦实战指南

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

导读

Envoy 的 adaptive concurrency(自适应并发控制)过滤器通过动态调整到上游集群的在途请求并发数,在过载时主动限流、在空闲时自动扩容。本指南聚焦该过滤器新增的min_concurrency_limit配置项——它首次允许把"计算出的并发下限"与"测量 minRTT 时使用的并发值"分开配置,为高延迟敏感业务提供了更精细的过载保护手段。读完本文,你将掌握该字段的配置语法、默认行为、源码级实现原理、运行时覆盖方式以及配套的统计指标与实战注意事项。

一、特性背景:changelog 与特性定位

该特性由 changelogs/current/new_features/http__adaptive_concurrency_min_concurrency_limit.rst 正式引入,原文描述如下:

Addedmin_concurrency_limitto the adaptive concurrency gradient controller to allow the minimum calculated concurrency limit to be configured separately from the concurrency used during minRTT recalculation.

(译文:在自适应并发梯度控制器中新增min_concurrency_limit,允许将"计算出的最小并发上限"与"minRTT 重算期间使用的并发"分开配置。)

在此之前,梯度控制器存在一个隐式耦合:计算并发下限与 minRTT 测量并发由同一个字段min_concurrency控制。新特性将其解耦,使运维者可以:

  • 保留较低的 minRTT 测量并发(保证理想延迟测量的准确性);
  • 同时设置一个更高的计算下限(避免正常运行期间并发被过度压低,减少不必要的 503)。

该字段的完整定义位于 api/envoy/extensions/filters/http/adaptive_concurrency/v3/adaptive_concurrency.proto 中GradientControllerConfig.ConcurrencyLimitCalculationParams消息的第 4 个字段(L53)。

二、梯度控制器工作原理回顾

要理解min_concurrency_limit,先要理解梯度控制器的运行机制。官方文档 docs/root/configuration/http/http_filters/adaptive_concurrency_filter.rst 指出,梯度控制器基于"周期性测量的理想往返时间(minRTT)"来做转发决策,其核心算法定义在 gradient_controller.h 的类注释中。

2.1 minRTT 的测量

控制器会周期性地将并发限制"钉死"在配置的min_concurrency上,在近乎理想的低并发条件下测量上游延迟,得到 minRTT。测量窗口的时长不固定,取决于配置的聚合请求数(request_count,默认 50)。

测量窗口的开启还引入了可配置的jitter(抖动)(默认 15%),用于随机延迟窗口的开始时间,避免集群内所有主机同时进入 minRTT 测量窗口(此时并发默认只有 3),从而缓解对下游成功率的影响。

2.2 梯度(gradient)的计算

梯度用采样请求延迟(sampleRTT)与 minRTT 的比值定义:

gradient = (minRTT + B) / sampleRTT B = minRTT * buffer_pct

其中buffer(默认 25%)允许采样延迟在超过 minRTT 一定阈值后才降低梯度值,从而容忍正常的延迟波动。gradient 值随采样延迟增大而减小,其取值范围被钳制在 [0.5, 2.0](见 gradient_controller.cc 的calculateNewLimit(),L194-L199),防止并发在两个采样窗口间发生极端变化。

2.3 并发上限的更新

每次采样窗口结束后,用下面的公式更新并发上限:

limit_new = gradient * limit_old + headroom

headroom(头部余量)用于在 sampleRTT 接近 minRTT 时驱动并发上升,避免并发停滞在过小的值上。它不可配置,固定为limit_new的平方根(sqrt(limit)),对应源码中的burst_headroom(L206-L207)。

最终计算出的新上限还会被钳制到[min_concurrency_limit, max_concurrency_limit]区间(L212-L213):

return std::max<uint32_t>(config_.minConcurrencyLimit(), std::min<uint32_t>(config_.maxConcurrencyLimit(), new_limit));

这正是min_concurrency_limit发挥作用的关键位置。

三、min_concurrency_limit 语义详解

3.1 旧行为 vs 新行为

维度旧行为(未配置 min_concurrency_limit)新行为(显式配置 min_concurrency_limit)
计算并发下限等于min_concurrency独立取值,与min_concurrency解耦
minRTT 测量并发min_concurrencymin_concurrency(不受影响)
适用场景保持历史兼容测量期间允许更激进的过载钳制,同时避免正常运行时并发过低

proto 注释明确了默认规则(adaptive_concurrency.proto L48-L53):

若未设置,该值默认为min_concurrency,以保持原有行为——同一个值同时控制最小计算上限与 minRTT 测量期间的并发。

官方文档 Minimum Concurrency Limit 一节 进一步强调:min_concurrency_limit决定的是"控制器在正常运行期间能把计算出的并发钳制到多低",而min_concurrency只决定"minRTT 测量期间的并发"。

3.2 源码中的默认值处理

gradient_controller.cc 的构造函数(L42-L47)展示了完整的默认值逻辑:

min_concurrency_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(proto_config.min_rtt_calc_params(), min_concurrency, 3)), min_concurrency_limit_(PROTOBUF_GET_WRAPPED_OR_DEFAULT( proto_config.concurrency_limit_params(), min_concurrency_limit, min_concurrency_)), min_concurrency_limit_configured_( proto_config.concurrency_limit_params().has_min_concurrency_limit()),

关键点:min_concurrency_limit的默认值直接取min_concurrency_(即 proto 中min_concurrency的值,该字段本身默认 3);min_concurrency_limit_configured_标记该字段是否被显式配置。

在 gradient_controller.h L93-L99 中,minConcurrencyLimit()的取值逻辑为:

uint32_t minConcurrencyLimit() const { if (!min_concurrency_limit_configured_) { return minRTTCalcConcurrency(); } return runtime_.snapshot().getInteger(RuntimeKeys::get().MinConcurrencyLimitKey, min_concurrency_limit_); }

即:未显式配置时直接复用 minRTT 测量并发;已配置时优先读取运行时覆盖,否则使用静态配置值。

3.3 minRTT 窗口内并发的特殊处理

当 minRTT 测量窗口开启时,控制器会记录窗口前的并发值(deferred_limit_value_),然后将并发钳制为"当前并发与 minRTT 测量并发的最小值"(L124-L126):

deferred_limit_value_.store(GradientController::concurrencyLimit()); updateConcurrencyLimit( std::min(GradientController::concurrencyLimit(), config_.minRTTCalcConcurrency()));

这意味着:如果当前并发已经低于 minRTT 测量并发,控制器不会为了测量而抬高并发,而是保留当前更低的并发。测量完成后(updateMinRTT(),L135-L157),再恢复deferred_limit_value_中的原并发。

四、完整配置示例与参数解析

4.1 官方示例配置(含 min_concurrency_limit)

以下配置来自官方文档 Example Configuration 并已包含新字段,可直接作为过滤器配置使用:

name: envoy.filters.http.adaptive_concurrency typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.adaptive_concurrency.v3.AdaptiveConcurrency gradient_controller_config: sample_aggregate_percentile: value: 90 concurrency_limit_params: concurrency_update_interval: 0.1s min_concurrency_limit: 25 min_rtt_calc_params: min_concurrency: 50 jitter: value: 10 interval: 60s request_count: 50 enabled: default_value: true runtime_key: "adaptive_concurrency.enabled"

官方对该示例的逐项解读:

  • 每 100ms 采样一个延迟窗口;进入新窗口时用该窗口样本汇总出 sampleRTT,并据此更新并发上限;
  • 汇总 sampleRTT 时使用所有采样延迟的 p90(90 分位);
  • 计算出的并发上限不会被压低到25以下(min_concurrency_limit);
  • 每 60s 重算一次 minRTT,并在窗口开始处引入 0s–6s 的随机延迟(jitter 10%);
  • minRTT 测量期间将并发钉在50min_concurrency),收集 50 个请求样本后以 p90 汇总;
  • 过滤器默认启用。

4.2 关键参数速查表

ConcurrencyLimitCalculationParams(并发上限计算参数)

参数默认值校验规则说明
concurrency_update_interval必填duration > 0采样窗口时长,即并发上限的更新周期
max_concurrency_limit1000uint32 > 0计算并发上限的最大值(上界钳制)
min_concurrency_limit等于min_concurrencyuint32 > 0计算并发上限的最小值(下界钳制);本特性新增字段

MinimumRTTCalculationParams(minRTT 测量参数)

参数默认值校验规则说明
interval>= 1msminRTT 重算周期;设为 0 表示禁用动态采样
fixed_valueduration > 0固定 minRTT 值;禁用动态采样时必须设置
request_count50uint32 > 0minRTT 重算窗口内聚合的请求样本数
jitter15%引入到 minRTT 窗口开始处的随机时间差(占 interval 的百分比)
min_concurrency3uint32 > 0minRTT 测量期间钉死的并发
buffer25%叠加到实测 minRTT 上的缓冲比例,用于容忍正常延迟波动

其他顶层参数(AdaptiveConcurrency)

参数默认值说明
gradient_controller_config必填梯度控制器配置(oneof,当前唯一控制器实现)
enabledtrueRuntimeFeatureFlag,false 时过滤器退化为透传
concurrency_limit_exceeded_status503并发超限时返回给下游的 HTTP 状态码;若配置值 < 400 则仍用 503

字段校验规则(gt: 0等)定义在 adaptive_concurrency.proto 的 validate 注解中,非法值会在配置加载阶段被拒绝。

五、运行时覆盖(Runtime Keys)

配置中的大部分参数都可通过运行时键实时覆盖,无需重启。完整清单如下(对应 gradient_controller.h L116-L133 中的 RuntimeKeyValues):

Runtime Key覆盖内容
adaptive_concurrency.enabled过滤器整体开关;false 时过滤器为 no-op
adaptive_concurrency.gradient_controller.min_rtt_calc_interval_msminRTT 重算间隔
adaptive_concurrency.gradient_controller.min_rtt_aggregate_request_countminRTT 计算的采样请求数
adaptive_concurrency.gradient_controller.jitterminRTT 计算开始时间的随机延迟(10 表示 10% 的间隔,钳制到 [0,100])
adaptive_concurrency.gradient_controller.sample_rtt_calc_interval_ms并发上限重算间隔
adaptive_concurrency.gradient_controller.max_concurrency_limit最大并发上限
adaptive_concurrency.gradient_controller.min_rtt_buffer计算并发上限时叠加到 minRTT 的缓冲
adaptive_concurrency.gradient_controller.sample_aggregate_percentile延迟样本的聚合分位数(95 表示 p95,钳制到 [0,100])
adaptive_concurrency.gradient_controller.min_concurrencyminRTT 测量期间钉死的并发;未配置min_concurrency_limit时兼作计算下限
adaptive_concurrency.gradient_controller.min_concurrency_limit最小计算并发上限(本特性新增);不影响 minRTT 测量期间钉死的并发

注意sample_aggregate_percentilejitter等百分比类运行时值会在 gradient_controller.h 的sampleAggregatePercentile()(L76-L80)与jitterPercent()(L83-L87)中被钳制并归一化到 [0.0, 1.0],源码中的双精度值(PROTOBUF_PERCENT_TO_DOUBLE_OR_DEFAULT解析)用于梯度计算。

六、统计指标

梯度控制器的指标位于命名空间http.<stat_prefix>.adaptive_concurrency.gradient_controller下,stat_prefix来自所属 HTTP 连接管理器的配置。指标定义见 gradient_controller.h L30-L37 的ALL_GRADIENT_CONTROLLER_STATS宏:

指标名类型说明
rq_blockedCounter被过滤器拦截的请求总数
min_rtt_calculation_activeGauge控制器是否正处于 minRTT 计算中(1/0)
concurrency_limitGauge当前并发上限
gradientGauge当前梯度值 × 1000(取值区间 500–2000,即梯度 0.5–2.0)
burst_queue_sizeGauge并发上限计算中的当前 headroom 值(即 sqrt(limit))
min_rtt_msecsGauge当前实测 minRTT(毫秒)
sample_rtt_msecsGauge当前聚合的 sampleRTT(毫秒)

注意gradient指标被放大 1000 倍以保留细节精度(源码注释引用了相关 issue,见 gradient_controller.cc L201-L203)。通过监控concurrency_limit是否长时间贴在min_concurrency_limit上,可以判断是否触发了下文所述的强制重测机制。

七、源码中的工程细节与测试佐证

7.1 连续触底的强制重测机制

gradient_controller.cc 的updateConcurrencyLimit()(L267-L291)实现了一个自适应防御逻辑:如果并发上限连续 5 个采样窗口都被设置为最小值(且当前不在 minRTT 测量中),说明 minRTT 测量可能已失真,控制器会立即触发一次 minRTT 重测(min_rtt_calc_timer_->enableTimer(0))。同时代码对窗口重叠做了防护:进入 minRTT 测量时(enterMinRTTSamplingWindow(),L106-L133)会先检查inMinRTTSamplingWindow()并持有sample_mutation_mtx_互斥锁,确保任意时刻只有一个测量窗口处于活跃状态。

7.2 单元测试验证解耦行为

新增字段的行为在 test/extensions/filters/http/adaptive_concurrency/controller/gradient_controller_test.cc 中有直接测试覆盖。例如GradientControllerConfigTest.BasicTest(L136-L164)使用如下配置:

sample_aggregate_percentile: value: 42.5 concurrency_limit_params: max_concurrency_limit: 1337 concurrency_update_interval: 0.123s min_concurrency_limit: 6 min_rtt_calc_params: jitter: value: 13.2 interval: 31s request_count: 52 min_concurrency: 8 fixed_value: 42s

并断言config.minRTTCalcConcurrency()为 8、config.minConcurrencyLimit()为 6——两个值完全独立,直接验证了"计算下限与测量并发解耦"的核心语义。其余测试用例(如 L307、L434、L468 处的min_concurrency_limit: 4/2)则用于验证钳制行为与窗口交互。集成测试见 adaptive_concurrency_filter_integration_test.h。

八、实战建议与注意事项

8.1 什么时候应该配置 min_concurrency_limit

官方文档建议:如果希望在过载时让控制器钳制得更激进(允许并发大幅下降),同时又不希望 minRTT 测量窗口内出现过多的 503,就应当min_concurrency_limitmin_concurrency分开配置。典型场景:

  • 低延迟高可用服务:测量期间用低并发(如 50)保证 minRTT 准确;正常运行期间将计算下限抬高(如 25)避免过度限流。官方示例正是这种"测量 50 / 下限 25"的组合。
  • 对 503 敏感的业务:测量窗口内并发骤降会带来可见的 503 上升(默认返回 503,见concurrency_limit_exceeded_status),通过解耦可以缩小这种影响。

8.2 重试策略

minRTT 测量期间可能出现明显的 503 增加(并发被压低所致),这是预期行为。官方建议:

  • 为 resets/503 启用重试;
  • 优先使用previous_hosts 重试谓词——由于 jitter 的存在,集群内所有主机同时进入 minRTT 窗口的概率很低,重试到集群内其他主机有更高的成功率。

8.3 过滤器链位置与适用限制

  • 官方建议将 adaptive concurrency 过滤器放在healthcheck 过滤器之后,防止健康检查流量被延迟采样而污染 minRTT 测量精度。
  • 过滤器存在固有适用限制(见 Limitations 一节):控制回路依赖延迟测量与并发调整,因此必须运行在能对请求并发拥有完全控制权的场景下——例如对本地集群的过滤器链生效,且必须能限制某集群的并发(即不允许存在绕过该过滤器而发往目标集群的请求)。

九、小结

min_concurrency_limit是对 Envoy 自适应并发梯度控制器的一次精准增强:它打破了min_concurrency长期"一值两用"的耦合,让运维者可以独立控制"理想条件测量"与"过载下限钳制"两个维度。结合源码可见,该字段贯穿配置解析(默认回退到min_concurrency)、运行时覆盖(adaptive_concurrency.gradient_controller.min_concurrency_limit)、并发钳制(calculateNewLimit()的上下界夹取)与防御性重测(连续 5 次触底触发 minRTT 重算)全链路,并有完整的单元测试背书。生产实践上,推荐配合 jitter、previous_hosts 重试谓词及concurrency_limit/gradient等指标,共同构建稳健的过载保护体系。

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

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

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

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

立即咨询