Envoy Composite Cluster用重试尝试次数把请求路由到不同上游集群【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy这篇文章讲解 Envoy 的 composite cluster 扩展它如何根据当前请求是第几次尝试attempt count把流量确定性地落到配置列表中的不同子集群上。读完你会知道ClusterConfig怎么写、lb_policy为什么必须配CLUSTER_PROVIDED、选中的子集群没有可用主机时 Envoy 会做什么以及重试策略该按什么规模来配。请求到底落在哪个集群映射关系完全由尝试次数决定composite cluster注册名envoy.clusters.composite解决的问题很具体你希望第 1 次尝试打到 A 集群、第 1 次重试打到 B 集群、第 2 次重试打到 C 集群而不是按子集群的健康比例分流。选择逻辑发生在每个 worker 线程本地的负载均衡器CompositeClusterLoadBalancer里路径在 source/extensions/clusters/composite/cluster.cc分三步取尝试次数getAttemptCount()cluster.cc#L45-L58从负载均衡上下文的StreamInfo中读取attemptCount()上下文为空或没有该值时回退为 0。换算成下标mapAttemptToClusterIndex()cluster.cc#L60-L77做 1 基转 0 基。attempt 1 → 下标 0attempt 2 → 下标 1。attempt_count 0视为非法值打印 warn 日志并返回nullopt下标超出配置集群数时同样返回nulloptconst size_t cluster_index attempt_count - 1; // attempt 1 → index 0 if (cluster_index clusters_-size()) { return cluster_index; } // Attempts exceed available clusters - fail the request. return std::nullopt;委托子集群选主机chooseHost()cluster.cc#L156-L170拿到下标后最终调用子集群自己的loadBalancer().chooseHost()round robin、maglev 等算法的选择完全由子集群完成。composite 本身不持有任何 host。与更常见的 aggregate cluster 相比两者定位不同AggregateComposite选择依据子集群健康状态重试尝试次数典型用途按健康的故障切换按尝试次序的降级演进尝试数超出配置取决于健康分布直接以 no host available 失败可预测性随健康变化确定性线程本地化是这里的性能关键CompositeLoadBalancerFactory在主线程创建一次由 cluster.h#L95-L107 的工厂在每个 worker 线程中create()出各自的CompositeClusterLoadBalancer子集群的增删更新通过构造函数中注册的addThreadLocalClusterUpdateCallbackscluster.cc#L42回调整步。配置长什么样一个只含集群名的列表配置消息是ClusterConfig定义在 api/envoy/extensions/clusters/composite/v3/cluster.proto#L45-L59。它只有一个字段clustersrepeated ClusterEntry校验规则min_items: 1子集群名列表顺序即尝试次序。ClusterEntry.name校验min_len: 1该集群必须在配置的其他位置独立定义——composite 自身不承载 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_clusterlb_policy必须是CLUSTER_PROVIDED负载均衡行为由扩展提供而不是由顶层策略指定。上面配置的运行时语义attempt 1 去primary_clusterattempt 2 去secondary_clusterattempt 3 去fallback_clusterattempt 4 起因下标越界而失败。每次委托子集群时原始上下文会被 lb_context.h 中的CompositeLoadBalancerContext包装哈希键、下游连接、优先级负载等全部透传额外只记录一个selected_cluster_index供调试。peekAnotherHost和selectExistingConnectioncluster.cc#L172-L208走同样的“先算下标、再委托”路径。选中的子集群没有可用主机时在同一尝试内向后 failover这是最容易误解的行为当 attempt 映射到的子集群一台主机都提供不了DNS 解析失败导致 endpoint 列表为空、或 outlier detection 把主机全部逐出composite cluster 不会立刻失败而是在同一次尝试内依次尝试列表中的下一个集群直到某个集群给出主机全部无主机的请求才以no_healthy_upstream失败。核心循环在selectHostWithFailover()cluster.cc#L112-L154for (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; } }两个细节异步主机选择不被打断子集群返回的cancelable非空意味着异步选择正在进行循环立即返回后续集群不再尝试——异步流程拥有选择过程的剩余部分。该行为有 runtime 开关envoy.reloadable_features.composite_cluster_skip_clusters_without_hosts默认开启开关声明见 source/common/runtime/runtime_features.cc#L42。设为false即回到旧行为映射到的集群无主机时当前尝试立即失败不向后找。这个开关对应的修复记录在 changelogs/current/bug_fixes/composite_cluster__skip-clusters-without-hosts.rst——修复前映射到的子集群无主机会误报503 no_healthy_upstream。重试策略怎么配才不浪费也不越界路由级必须配一个与子集群数量对齐的retry_policyretry_policy: retry_on: 5xx,gateway-error,connect-failure,refused-stream num_retries: 2 # 1 次初始请求 2 次重试 3 次尝试对齐规则很直接num_retries 1应等于clusters列表长度。配多了一次超出的尝试在下标换算时返回nullopt请求以无可用主机失败配少了靠后的子集群永远轮不到。还有两条行为约束需要注意failover 不移动后续尝试的映射。例如列表是[primary, secondary, fallback]且primary为空attempt 1 因 primary 无主机落到secondary但 attempt 2 依然映射到secondary不是fallback。映射只由尝试次数驱动failover 是“就地补偿”而非“推进指针”。健康度不用于分流。composite 不用子集群健康度在它们之间分摊流量健康信息只参与“跳过完全给不出主机的子集群”这一步。只要目标子集群可用对应尝试就稳定命中它。仓库里怎么验证这些行为单元测试test/extensions/clusters/composite/cluster_test.cc 覆盖集群创建、attempt count 提取含空上下文、无 StreamInfo 等边界、下标映射0 值、1→0、2→1、越界值见 cluster_test.cc#L155-L163以及 failover 行为包括关闭 runtime 开关后回退旧行为的用例。集成测试test/extensions/clusters/composite/cluster_integration_test.cc 用 3 个 fake upstream 1 个 composite 集群做端到端验证典型用例包括BasicRetryProgression验证 cluster_0 → cluster_1 → cluster_2 的演进OverflowFails验证num_retries: 5超出 3 个集群时第 4 次尝试失败FailsOverWhenClusterHasNoEndpoints在num_retries: 0下验证“cluster_0 无 endpoint 时首次尝试直接打到 cluster_1 且upstream_rq_retry计数为 0”——证明 failover 发生在单次尝试内、不消耗重试额度AttemptCountVerification通过include_request_attempt_count等开关断言每次尝试命中的集群与 attempt 计数头。配置校验proto 的 validate 规则保证clusters非空、集群名非空串错误在配置加载阶段暴露。架构文档 docs/root/intro/arch_overview/upstream/composite_cluster.rst 列出了该扩展面向的场景primary → secondary → tertiary 的按重试降级、AI Gateway 的多提供商故障切换初始请求走首选提供商重试切备用、以及“先贵后廉”的成本优化路由。三者的共同点是流量走向要由尝试次序而非健康比例决定——这正是cluster_index attempt_count - 1这条映射要表达的。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考