news 2026/9/17 18:51:10

Envoy Composite Cluster 详解:基于重试次数的确定性上游集群选择机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Envoy Composite Cluster 详解:基于重试次数的确定性上游集群选择机制

Envoy Composite Cluster 详解:基于重试次数的确定性上游集群选择机制

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

Envoy 的 Composite Cluster 扩展把"重试演进"固化为一种集群类型:子集群列表的顺序就是重试尝试的次序,第 N 次尝试确定性地路由到第 N 个子集群,而不再由健康状态比例决定流量走向。读完本文,你会掌握它的配置方法、attempt count 到集群下标的源码映射链路、无主机时的回退(failover)边界行为,以及与路由重试策略的配套关系。

痛点:重试打到哪里,你说了不算

Envoy 路由的重试机制解决的是"要不要再试一次",但没回答"这一次试谁"。默认情况下重试仍然落在原集群,由原集群的负载均衡算法(round robin、maglev 等)在现有主机里挑一个——对多提供商、多成本档位的上游架构来说,这远远不够:你希望第一次请求走首选供应商,第一次重试切到备用供应商,第二次重试落到最便宜的兜底服务,并且每次尝试的落点可预期、可复现。

Aggregate Cluster 看起来接近,但它的顶层负载均衡按各子集群的健康状态分流,结果取决于健康度快照,天然带不确定性。Composite Cluster 的选路依据只有一个:当前请求是第几次尝试。两者定位不同:

维度Aggregate ClusterComposite Cluster
选择依据子集群健康状态重试尝试次数
适用目标按健康比例容灾按次序确定性降级
超出容量取决于健康状态请求直接失败

Composite Cluster 配置方法:列表顺序即尝试次序

配置消息是 ClusterConfig,扩展注册名envoy.clusters.composite。它只有一个字段clustersrepeated ClusterEntry,校验min_items: 1),每个ClusterEntry只有一个name(校验min_len: 1)。被引用的子集群必须在配置的其他位置独立定义——Composite Cluster 自身不承载 endpoint、负载均衡算法或健康检查。

name: composite_cluster connect_timeout: 0.25s lb_policy: CLUSTER_PROVIDED cluster_type: name: envoy.clusters.composite typed_config: "@type": type.googleapis.com/envoy.extensions.clusters.composite.v3.ClusterConfig clusters: - name: primary_cluster - name: secondary_cluster - name: fallback_cluster

关键字段到运行时行为的对应关系:

  • lb_policy: CLUSTER_PROVIDED→ 主机选择完全委托给被选中的子集群,Composite 自身无 host;
  • clusters[0].name→ attempt 1(初始请求)的目标;
  • clusters[1].name→ attempt 2(第一次重试)的目标;
  • clusters[2].name→ attempt 3(第二次重试)的目标;
  • attempt 4 及以后 → 下标越界,请求以 no host available 失败。

源码机制:attempt count 到 cluster index 的三步链路

选择逻辑全部发生在 worker 线程本地的负载均衡器里,实现集中在 cluster.cc。入口chooseHost()(cluster.cc#L156-L170)的链路是"提取 → 映射 → 委托":

第一步,提取尝试次数。getAttemptCount()(cluster.cc#L45-L58)从LoadBalancerContextrequestStreamInfo(),读其中的attemptCount();上下文或 StreamInfo 为空时回退为 0。

第二步,1 基转 0 基。mapAttemptToClusterIndex()(cluster.cc#L60-L77)做纯算术映射:

if (attempt_count == 0) { ENVOY_LOG(warn, "invalid attempt count 0 ..."); return std::nullopt; } const size_t cluster_index = attempt_count - 1; // attempt 1 → index 0 if (cluster_index < clusters_->size()) { return cluster_index; } return std::nullopt; // 越界:请求失败

第三步,委托子集群选主机。拿到下标后selectHostWithFailover()通过getClusterByIndex()cluster_manager_.getThreadLocalCluster()取到子集群的ThreadLocalCluster,用 lb_context.h 中的CompositeLoadBalancerContext包装原始上下文后,调用cluster->loadBalancer().chooseHost()由子集群自己的负载均衡算法完成最终主机选择。peekAnotherHostselectExistingConnection(cluster.cc#L172-L208)走同样的"先映射下标、再委托"路径,但只针对映射到的单个集群,不做 failover 遍历。

线程模型上,cluster.h 中Cluster继承自ClusterImplBaseinitializePhase()返回Secondary(等待被引用的子集群先初始化完成);CompositeLoadBalancerFactory在每个 worker 线程内各自创建一个CompositeClusterLoadBalancer,后者构造时通过addThreadLocalClusterUpdateCallbacks注册回调整步子集群的增删,选择路径本身无跨线程开销。

边界行为:越界尝试与同一尝试内的 failover

两组边界行为值得逐条确认。

越界尝试。attempt_count == 0属异常状态,打 warn 日志并返回nullopt;重试次数超过子集群数时(例如配置 3 个子集群却有 attempt 4)同样返回nulloptchooseHost返回空主机,请求以 no host available 失败。这正是"子集群数量应与重试总尝试次数对齐"的底层原因。

同一尝试内 failover。映射到的子集群若拿不出任何主机(DNS 解析返回空 endpoint 列表、或被 outlier detection 全部逐出),selectHostWithFailover()(cluster.cc#L112-L154)会从该下标起向后遍历,直到某个集群能返回主机;全部失败才以no_healthy_upstream结束:

for (size_t cluster_index = start_index; cluster_index < clusters_->size(); ++cluster_index) { auto* cluster = getClusterByIndex(cluster_index); if (cluster != nullptr) { CompositeLoadBalancerContext composite_context(context, cluster_index); response = cluster->loadBalancer().chooseHost(&composite_context); if (response.host != nullptr || response.cancelable != nullptr) { return response; // 选到主机或异步选择进行中,立即返回 } } if (!skip_clusters_without_hosts) { break; // 开关关闭时,第一个无主机的集群即终止 } }

两个细节:

  1. 若子集群返回的cancelable非空(异步主机选择进行中),循环立即返回,不再尝试后续集群——异步流程拥有选择过程的全部后续;
  2. 该行为受 runtime 开关envoy.reloadable_features.composite_cluster_skip_clusters_without_hosts保护(默认开启)。设为false回退旧行为:映射到的子集群无主机则本次尝试立即失败,不做向后 failover。对应修复见 composite_cluster__skip-clusters-without-hosts.rst,解决的正是"无主机时误报 503 no_healthy_upstream"的问题。

还有一个容易踩的点:failover 不移动后续尝试的映射。映射由尝试次数驱动,配置[primary, secondary, fallback]primary为空时,attempt 1 因 primary 无主机落到 secondary,attempt 2 依然映射 secondary(而非 fallback)。设计重试规模时要按这个语义预留余量。

重试策略配套:让次数与集群数对齐

Composite Cluster 依赖路由级重试策略提供"尝试次数"这个输入信号:

retry_policy: retry_on: "5xx,gateway-error,connect-failure,refused-stream" num_retries: 2 # 共 3 次尝试:attempt 1、2、3

num_retries: 2意味着 1 次初始 + 2 次重试 = 3 次尝试,恰好覆盖上文三个子集群。配大了,超出的尝试越界失败;配小了,尾部的兜底集群用不上。集成测试 cluster_integration_test.cc 按 3 个静态子集群 + 1 个 composite 集群构造场景,路由设置retry_on: "5xx",并借助include_request_attempt_count/include_attempt_count_in_response回显每次尝试实际命中的集群;单元测试 cluster_test.cc 则覆盖 null 上下文、无 StreamInfo、越界值等getAttemptCount边界,以及关闭 runtime 开关后的旧行为回退。

何时用、注意什么

Composite Cluster 适合"按次序降级"而非"按健康分流"的架构:AI Gateway 多提供商故障切换(首选模型 → 备用供应商)、成本分级路由(先打昂贵高性能服务、失败回退便宜服务)、以及任何需要重试落点完全可预测的场景。

使用时把握三条纪律:📌lb_policy必须为CLUSTER_PROVIDED,子集群数量与num_retries + 1严格对齐;⚠️ 每个子集群独立维护健康检查、负载均衡与 outlier detection,Composite 只负责"选哪个子集群";⚠️ 同一尝试内的 failover 只影响当前尝试,不会推移后续尝试的映射,重试策略的规模要按此语义设计。

完整语义说明可对照架构文档 composite_cluster.rst,与 aggregate 集群的对比章节在其中。

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 18:48:50

STM32 Bootloader与串口IAP实现:从原理到代码,轻松搞定固件升级

很多人刚接触单片机开发时&#xff0c;对 bootloader 总是有一种“高深莫测”的感觉。后来我自己做产品&#xff0c;才真正意识到它其实就是一段“先于主程序运行的小程序”&#xff0c;并没有想象中复杂。尤其是当你需要给已经出货的设备做固件升级时&#xff0c;IAP&#xff…

作者头像 李华
网站建设 2026/9/17 18:45:21

S7-1500 PLC硬件配置、电源预算与硬件诊断实战

简介&#xff1a;这份《S7-1500 PLC应用技术》第2章课件&#xff0c;面向自动化、电气控制专业学生及初学S7-1500的工程人员&#xff0c;用于梳理该系列PLC硬件体系与选型要点。内容分六部分&#xff1a;SIMATIC产品定位、CPU模块、电源模块、信号模块、通信模块与CPU操作模式。…

作者头像 李华
网站建设 2026/9/17 18:41:18

VS2015安装包损坏修复全指南:校验、离线重建与工具链提取

1. 这不是“重装就完事”的问题&#xff1a;VS2015安装包损坏/丢失的真实战场你点开那个下载了三小时的 vs2015community.exe&#xff0c;双击后弹出“无法验证安装包完整性”、“找不到 bootstrapper.exe”、“setup.exe 已损坏”——不是你的网速慢&#xff0c;也不是磁盘满了…

作者头像 李华
网站建设 2026/9/17 18:40:56

UML用例模型实战:用例图、规格说明与需求评审避坑

用例模型是UML里最容易被低估的一块内容。用例图谁都能画几个小人加圆圈&#xff0c;但真正能拿去评审、能撑起后续设计与测试的用例模型&#xff0c;十份里挑不出一份。用例图解决的是"系统边界在哪、谁跟系统打交道、系统对外承诺做什么"这三个问题&#xff0c;用例…

作者头像 李华
网站建设 2026/9/17 18:40:09

用项目管理与经济决策框架复盘自媒体创业

简介&#xff1a;一份北京邮电大学信息与通信工程学院《项目管理与经济决策》课程期末论文&#xff0c;主题为自媒体创业项目经历分析&#xff0c;适合正在修读该课程或需要撰写项目管理类课程论文的本科生参考。论文以作者真实自媒体创业过程为对象&#xff0c;系统运用项目工…

作者头像 李华