ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Envoy 子集负载均衡(Load Balancer Subsets):基于主机元数据的精细流量分发实战

Envoy 子集负载均衡(Load Balancer Subsets):基于主机元数据的精细流量分发实战 Envoy 子集负载均衡Load Balancer Subsets基于主机元数据的精细流量分发实战【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoyEnvoy 允许按上游主机Host携带的元数据把集群内的端点划分为若干子集Subset并在路由层通过元数据匹配条件选择命中哪些主机未命中时还可按预定义的回退fallback策略兜底。本文以官方架构文档中的 Load Balancer Subsets 章节为主体完整继承其中的配置示例与行为表格并结合 Envoy 仓库中 subset 负载均衡器的真实源码subset_lb.cc与 API 定义cluster.proto讲清子集如何构建、如何匹配、回退如何生效以及单主机子集、本地性感知等进阶能力。读完本篇你可以直接写出可用的lb_subset_config与路由metadata_match配置并理解每条行为背后的实现依据。一、核心概念元数据驱动的端点分片Envoy 可以配置成根据附加在主机上的元数据把某个上游集群内的主机划分为若干子集。路由随后可以指定主机必须匹配哪些元数据才能被负载均衡器选中并支持回退到一组预定义的、甚至包括任意主机在内的端点集合。几个关键规则均来自架构文档且在源码中得到印证子集复用集群自身的负载均衡策略。子集内部仍使用集群配置的 LB 策略逐主机选点但原始目的地策略ORIGIN_DST不能用于子集因为上游主机是事先未知的。与区域感知路由zone aware routing兼容但要注意子集划分后很容易不满足区域感知路由所要求的最小主机数条件。子集必须先预定义以便子集负载均衡器能高效地选中正确的主机组。每条定义是一组 key会派生出零个或多个子集。从源码结构看实现上是一个 trie 式的层级结构LbSubsetMapkey → value → LbSubsetEntry的嵌套哈希表在 subset_lb.h 中被注释为 Forms a trie-like structure. Requires lexically sorted Host and Route metadata要求主机与路由元数据按键的字典序排列查找时逐级下探任一级 key 或 value 缺失即判定无子集。概念上每个在全部 key上都有元数据值的主机会被加入与其键值对对应的那个子集如果没有任何主机具备全部 key则该定义不产生任何子集。可以给出多条定义单个主机若匹配多条定义可同时出现在多个子集中。路由阶段使用路由的 metadata match 配置来定位具体子集只有当子集的 key 与 value 与路由完全一致时才使用该子集否则走回退策略。因此集群的 subset 配置中必须包含一条与路由相同的 key 集合的定义子集负载均衡才会真正发生。主机元数据只有在主机通过ClusterLoadAssignments即 EDS 或集群的load_assignment字段定义时才被支持子集负载均衡所用的主机元数据必须放在envoy.lb这个 filter 命名空间下路由的 metadata match 条件同样使用envoy.lb。源码中这一约束体现在 subset_lb.cc 的extractSubsetMetadata与hostMatches前者从metadata.filter_metadata()中按MetadataFilters::get().ENVOY_LB取值后者调用Config::Metadata::metadataLabelMatch并在同一命名空间下比对。主机元数据可以是层次化的例如某个顶层 key 的值是结构体或列表但子集负载均衡器只比较顶层的 key 和 value。因此使用结构化值时只有当主机元数据中出现与路由匹配条件完全相同的结构化值时才会命中。最后CLUSTER_PROVIDED 负载均衡策略不支持子集负载均衡。二、回退Fallback策略体系当配置了子集但路由没有指定元数据、或找不到与元数据匹配的子集时子集负载均衡器启动回退策略。集群级默认策略是NO_FALLBACK请求会像集群没有主机一样失败。文档定义了三档集群级策略且允许为单个 subset selector 覆盖回退策略——这一点在 API 与源码中都得到确认策略行为NO_FALLBACK默认请求失败等价于集群无健康主机ANY_ENDPOINT忽略主机元数据在集群全部主机上做负载均衡仍受健康检查等约束DEFAULT_SUBSET在匹配default_subset指定元数据的主机之间做负载均衡在 cluster.proto 中集群级枚举LbSubsetFallbackPolicy仅含这三个值而 selector 级的LbSubsetSelectorFallbackPolicy多出两个见 proto 定义NOT_DEFINED表示未覆盖沿用集群级策略KEYS_SUBSET把元数据 key 缩减为该 selector 指定的fallback_keys_subset然后重新执行一次子集选择允许部分 key 视为可选回退到更宽泛、更不具体的 selector。源码中这套逻辑的对应关系非常清晰subset_lb.cc构造期initSubsetSelectorMap把每个 selector 的 key 序列插入一棵 trie 式的selectors_树并在 selector 最后一个 key 对应的节点上挂上该 selector 的fallback_params_策略 fallback_keys_subset选主机时chooseHostIteration先调用tryChooseHostFromContext走正常子集查找findSubset若查无子集tryFindSelectorFallbackParams用路由匹配条件在 selector trie 上逐级下探找到完整前缀匹配的 selector 后chooseHostForSelectorFallbackPolicy按其策略执行ANY_ENDPOINT用subset_any_、DEFAULT_SUBSET用subset_default_、KEYS_SUBSET则用LoadBalancerContextWrapper过滤出缩减后的匹配条件并递归再次调用chooseHostIteration若 selector 级策略为NOT_DEFINED最终落到集群级fallback_subset_subset_any_或subset_default_命中时会累加统计lb_subsets_fallback_。除文档正文提到的三种策略外LbSubsetConfig还提供两个相关的辅助开关理解它们有助于排障见 cluster.protopanic_mode_any当已配置的回退子集找不到主机时例如DEFAULT_SUBSET对应的默认子集恰好为空改为从整个集群任选一个主机list_as_any路由元数据可以是标量或列表命中条件放宽为端点元数据与标量值精确相等或端点元数据是列表且其中任一元素匹配。源码中extractSubsetMetadata在开启该选项时会把端点的列表值展开为多组键值组合笛卡尔积使一个主机可挂入多个子集。此外还有metadata_fallback_policy默认METADATA_NO_FALLBACK设为FALLBACK_LIST时路由元数据中可携带一个特殊键fallback_list值为列表每个元素是 struct负载均衡按顺序用路由元数据与列表项合并后的结果重试直到选出主机fallback_list键本身会在子集负载均衡前从元数据中剔除。源码对应chooseHost→chooseHostWithMetadataFallbacks的实现。三、官方配置示例与行为对照表以下示例完整继承自架构文档假定集群中定义了如下四台主机及其元数据主机元数据host1v: 1.0, stage: prodhost2v: 1.0, stage: prodhost3v: 1.1, stage: canaryhost4v: 1.2-pre, stage: dev集群侧启用子集负载均衡的配置如下--- name: cluster-name type: EDS eds_cluster_config: eds_config: path: .../eds.conf connect_timeout: seconds: 10 lb_policy: LEAST_REQUEST lb_subset_config: fallback_policy: DEFAULT_SUBSET default_subset: stage: prod subset_selectors: - keys: - v - stage - keys: - stage fallback_policy: NO_FALLBACK这里lb_policy: LEAST_REQUEST说明子集内部沿用了集群级负载均衡策略。两条 selector 分别覆盖两键子集vstage和一键子集stage并且第二条 selector 用NO_FALLBACK覆盖了集群级的DEFAULT_SUBSET。按此配置各路由匹配条件的实际效果如下文档原表匹配条件负载均衡对象原因stage: canaryhost3命中子集一键 selectorv: 1.2-pre, stage: devhost4命中子集两键 selectorv: 1.0host1, host2回退不存在仅含 v 的 selector走集群级DEFAULT_SUBSETstage: prodother: xhost1, host2回退不存在 other 的 selector无元数据host1, host2回退未请求子集stage: test空集群stageselector 的回退策略被覆盖为NO_FALLBACK最后一行最能体现 selector 级覆盖的威力虽然集群级回退是DEFAULT_SUBSET但由于命中了keys: [stage]这条 selector 的前缀其私有策略NO_FALLBACK生效stage: test找不到主机即失败。源码中tryFindSelectorFallbackParams在 trie 上找到完整匹配后返回该节点参数chooseHostForSelectorFallbackPolicy中NO_FALLBACK分支直接返回{nullptr}与文档行为一一对应。加权集群weighted clusters上的元数据合并规则同样值得注意匹配条件来自被选中的加权集群会与路由自身的条件合并且覆盖路由条件文档原表路由匹配条件加权集群匹配条件最终匹配条件stage: canarystage: prodstage: prodv: 1.0stage: prodv: 1.0, stage: prodv: 1.0, stage: prodstage: canaryv: 1.0, stage: canaryv: 1.0, stage: prodv: 1.1, stage: canaryv: 1.1, stage: canary无v: 1.0v: 1.0v: 1.0无v: 1.0从源码看该合并由LoadBalancerContextWrapper的mergeMatchCriteria构造器完成即在进入子集查找前把覆盖 struct 合入路由元数据。四、端到端配置带元数据的主机与路由带元数据的主机EDS 下发的LbEndpoint中元数据必须挂在filter_metadata.envoy.lb下文档原例--- endpoint: address: socket_address: protocol: TCP address: 127.0.0.1 port_value: 8888 metadata: filter_metadata: envoy.lb: version: 1.0 stage: prod带匹配条件的路由RDSRoute通过metadata_match指定条件同样位于envoy.lb命名空间文档原例--- match: prefix: / route: cluster: cluster-name metadata_match: filter_metadata: envoy.lb: version: 1.0 stage: prod实际使用中匹配条件通常与路径、头部等请求特征绑定使访问某路径/带某头部的请求落到特定版本或环境的子集上——例如金丝雀发布时把stage: canary子集只暴露给灰度流量。metadata_match字段的定义可参考 route_components.proto。五、单主机子集、本地性感知与实现细节单主机子集single_host_per_subset子集可以被配置为每个子集只含一个主机。这适用于类似 Maglev、ring hash 的场景——例如基于 cookie 做负载均衡且希望即使集群新增了主机选中的还是同一台。从源码结构看这类子集使用专门的SingleHostLbSubsetpushHost每个优先级只保留一个主机指针finalize时直接替换subset_避免了完整HostSet的增删簿记因此端点配置变更时的 CPU 开销更低。若配置中同一 key 对应了多个主机只会选用其中一个重复数量由集群 gaugelb_subsets_single_host_per_subset_duplicate反映便于发现配置问题。本地性感知locality_weight_aware/scale_locality_weight子集划分会缩小各本地性的主机规模若仍沿用原始本地性权重可能出现文档与 proto 注释都提到的流量倾斜陷阱——例如 X/Y 两个本地性原本 50/50 各 100 台主机子集命中后 X 只剩 1 台而 Y 有 100 台单台主机会承受远超预期的负载。开启locality_weight_aware让子集路由计入本地性与本地性权重配合scale_locality_weight时subset_lb.cc 中determineLocalityWeights会按子集内主机数 / 原本地性主机数的比例缩放各本地性权重缓解这种倾斜。子集的动态维护subset LB 在构造时对原PrioritySet注册了优先级更新回调每当主机集合变化update会对每个主机、每条 selector 调用extractSubsetMetadata抽取键值对列表值在list_as_any下展开经findOrCreateLbSubsetEntry在 trie 中定位或创建条目再pushHost增量更新各子集的HostSet最后purgeEmptySubsets清理空子集并修正lb_subsets_active_等统计。相关可观测指标lb_subsets_selected_、lb_subsets_fallback_、lb_subsets_fallback_panic_等在chooseHostIteration的关键分支上递增配合 admin 统计可以直观判断流量是命中子集还是走了回退。异步与连接复用限制SubsetLoadBalancer的chooseHost结果被onlyAllowSynchronousHostSelection包裹且未实现peekAnotherHost、selectExistingConnection等接口——从源码结构看子集路径下的主机选择是同步完成的依赖异步连接选择或特定连接复用的 LB 能力在子集场景下不可用。六、配置检查清单综合文档与源码落地子集负载均衡时建议逐项核对主机来自ClusterLoadAssignmentsEDS 或load_assignment元数据位于envoy.lb命名空间且只用顶层 key/value 参与比较subset_selectors中的 key 集合必须与路由metadata_match的 key 集合存在完全一致的对应关系否则永远走回退集群级fallback_policy默认为NO_FALLBACK需要兜底时显式设为ANY_ENDPOINT或DEFAULT_SUBSET并给出default_subsetselector 级可用LbSubsetSelectorFallbackPolicy覆盖含KEYS_SUBSET的降级选择此时必须设置非空的fallback_keys_subset且不能与keys相同LB 策略不是ORIGIN_DST或CLUSTER_PROVIDED多本地性部署且子集会显著改变本地性规模时评估locality_weight_aware/scale_locality_weight需要新主机加入后仍选中同一主机时使用单键 selector single_host_per_subset并通过lb_subsets_single_host_per_subset_duplicategauge 监控重复。以上规则与示例均可在当前仓库中复核架构文档见 subsets.rstAPI 定义见 LbSubsetConfig核心实现见 subset 负载均衡器 与 subset_lb.h相关统计项定义于ClusterLbStatslb_subsets_*系列。按这套配置与回退机制Envoy 可以在不改变集群拓扑的前提下把按版本、按环境、按硬件规格选主机这类灰度与金丝雀流量策略下沉到负载均衡层。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表