尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Envoy Composite Cluster 原理、配置要点与避坑指南

Envoy Composite Cluster 原理、配置要点与避坑指南 Envoy Composite Cluster 原理、配置要点与避坑指南【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy同一个请求重试一次上游供应商就换了。这是 Envoy Composite Clusterenvoy.clusters.composite的核心行为它不看子集群健康状态而是按**重试尝试次数retry attempt count**决定请求落到哪个子集群。首次请求、第一次重试、第二次重试分别命中配置列表里的第 1、2、3 个集群全部由一个下标换算公式驱动。为什么按健康状态选集群不够用Aggregate Cluster把多个子集群聚合成一个逻辑集群的扩展回答的问题是此刻哪个子集群更可用它的流量分配随健康状态波动某子集群被 outlier detection 逐走一批主机权重随之下降。这种按可用比例分流在故障切换场景是优点但在需要按次序降级的场景是缺陷——你无法保证第一次重试一定打到备用供应商也无法让不同尝试承担不同成本档位因为每次选谁都由当时的健康分布决定路径不可预测。Composite Cluster 把决策输入从健康状态换成了尝试序号。两者差异的根源只有一条Aggregate ClusterComposite Cluster决策输入各子集群当前的健康状态权重随健康波动当前请求是第几次尝试固定序号不随健康变化换句话说aggregate 的决策是概率性的同样的重试今天打到 A 明天可能打到 Bcomposite 的决策是查表同样的第 N 次尝试永远映射到列表里第 N 个位置前提是那个子集群能提供主机。对 AI Gateway 多提供商切换、贵服务优先、廉价服务兜底这类场景后者才是能写进 SLO 的行为。三分钟看懂它的运行方式最小可用配置如下。子集群必须在此处之外的别处独立定义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_clusterclusters是唯一的配置字段列表顺序就是尝试次序。cluster.proto 的 validate 规则要求列表非空且集群名非空串配置加载阶段就能拦住笔误。给定上述配置与路由上num_retries: 2的重试策略一次请求的生命周期是尝试 1初始请求→primary_cluster尝试 2第一次重试→secondary_cluster尝试 3第二次重试→fallback_cluster尝试 4 及以后 → 无可用主机请求失败核心换算关系只有一行cluster_index attempt_count - 1用大白话说Envoy 的路由器把请求记为第几次发出去从 1 开始数集群列表是 C 数组从 0 开始数。减掉 1第几次尝试就落在第几个集群上仅此而已。源码中的三次决策系统如何知道当前是第几次尝试CompositeClusterLoadBalancer::getAttemptCount()从负载均衡上下文的requestStreamInfo()里读出attemptCount()见 cluster.cc#L45-L58。上下文为空或 StreamInfo 里没有尝试计数时一律按 0 处理——这个值随后会被映射函数当作异常拒绝而不是默默命中第一个集群。次数如何变成集群下标越界怎么办映射函数对 1 基数做减法并对两种异常直接返回nulloptif (attempt_count 0) { ENVOY_LOG(warn, invalid attempt count 0 ...); return std::nullopt; } const size_t cluster_index attempt_count - 1; if (cluster_index clusters_-size()) { return cluster_index; } // Attempts exceed available clusters - fail the request. return std::nullopt;这段逻辑把重试比集群多变成一次显式失败nullopt最终表现为 no host available而不是悄悄回落到最后一个集群。边界上attempt_count 0只打 warn 日志不报错而越界只打 debug 日志——两个分支的日志等级不对称排查时以请求结果为准。下标确定后主机由谁最终选择子集群只负责选哪个集群这一层集群内部选哪台主机完全委托给该子集群自己的负载均衡器round robin、maglev 等Composite Cluster 不介入。同一尝试内向后 failover 的循环如下for (size_t cluster_index start_index; cluster_index clusters_-size(); cluster_index) { auto* cluster getClusterByIndex(cluster_index); if (cluster ! nullptr) { response cluster-loadBalancer().chooseHost(composite_context); if (response.host ! nullptr || response.cancelable ! nullptr) { return response; // 选到主机或异步选择已在途立即返回 } } if (!skip_clusters_without_hosts) { break; // 关闭 failover 时第一个无主机的集群即终止 } }这个循环从映射出的下标出发逐个向后问子集群你有主机吗。委托用的CompositeLoadBalancerContextlb_context.h透传原始上下文的全部方法并额外记录selected_cluster_index方便调试时知道请求最终落在哪个位置peekAnotherHost与selectExistingConnection走的是同一条先映射下标、再委托的路径。边界行为与容易踩的坑同一尝试内向后 failover现象attempt 1 配置的primary_cluster没打到实际落在secondary_cluster且envoy.request.attempt仍是 1。触发条件映射到的子集群没有任何可用主机——DNS 解析失败导致 endpoint 列表为空或 outlier detection 把全部主机逐出。后果该尝试在列表内继续向后找直到有集群能给出主机全部无主机才以no_healthy_upstream失败。注意 failover 不移动后续尝试的映射primary 为空时attempt 2 依然映射到secondary而不是fallback。运行时开关envoy.reloadable_features.composite_cluster_skip_clusters_without_hosts现象默认开启时发生上述向后 failover设为false后映射到的子集群无可用主机则立即失败。触发条件显式修改该 runtime 开关。后果行为回退到旧版本语义——无 failover直接 503。变更说明见 changelogs/current/bug_fixes/composite_cluster__skip-clusters-without-hosts.rst修复的正是子集群无主机时误报 503 no_healthy_upstream。异步主机选择不被打断现象某个子集群正在做异步选择时后面的集群一律不会被尝试。触发条件子集群chooseHost()返回的cancelable非空异步选择已在途。后果循环立即返回该响应由异步流程拥有后续全部选择这是有意设计避免同一请求被两个子集群各选出一台主机。尝试次数超出集群数量现象请求直接失败返回 503 no host available。触发条件路由num_retries过大使总尝试次数超过clusters列表长度。后果映射函数返回nullopt无 failover 可言。子集群数量应与重试策略的总尝试次数1 num_retries对齐而不是只与num_retries对齐。怎么确认它在按预期工作路由上打开两个开关virtual_host级别让每次尝试的序号可被外部观测include_request_attempt_count: true include_attempt_count_in_response: true开启后请求与响应头会携带尝试计数对照envoy.upstream.cluster访问日志字段即可确认第 N 次尝试打到了哪个集群。仓库内的验证入口有两处单元测试 test/extensions/clusters/composite/cluster_test.cc覆盖集群创建、attempt count 提取含空上下文、无 StreamInfo、越界值、下标映射与 failover并包含关闭 runtime 开关后回退旧行为的用例。集成测试 test/extensions/clusters/composite/cluster_integration_test.cc3 个静态子集群 1 个 composite 集群路由retry_on: 5xx其中BasicRetryProgression用例让三个 fake upstream 依次返回 503、503、200断言cluster.cluster_N.upstream_rq_total各恰好为 1并可用addClusterWithoutEndpoints构造endpoint 列表为空的场景端到端验证同一尝试内 failover。上线前自查 3 条集群的lb_policy取值为CLUSTER_PROVIDED——composite 自己不做负载均衡该取值表示选择完全委托子集群。重试总尝试次数1 num_retries与clusters列表长度相等多一次则越界失败少一次则尾部集群永远命中不到。接受 failover 不移动后续映射的事实primary 长期为空时attempt 1 和 attempt 2 会连续命中 secondary重试预算没有花在降级路径上需据此规划重试规模。一句话界定边界它适合重试路径必须可预测的降级与切换多 AI 提供商、成本分级路由不适合按健康比例分摊流量的负载聚合——后者请继续用 Aggregate Cluster。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表