Router 终局给出的是一个 cluster 名。真正决定「流量落在哪台机器」的,是 Cluster 上的负载均衡策略、优先级与 locality、以及(可选)subset 元数据。路由正确仍可能把流量打进空子集或错误优先级——本文钉 Cluster 模型与选主层次,不写连接池限额与 outlier 全书(见 第 8 篇),也不写健康检查配置百科。
本文是「Envoy / 数据面代理内核」系列第 7 篇(共 16 篇)。→ 系列目录
篇目 核心内容 第 6 篇 · HTTP filter / Router 终端路由 第 7 篇 · Cluster / LB 优先级、locality、subset 第 8 篇 · 连接池 / outlier 资源限额与驱逐 上一篇:HTTP filter 与 Router · 下一篇:连接池、熔断与 outlier
版本锚定:Envoy v1.39.0 Supported load balancers、Priority levels、Load Balancer Subsets(文档树;subset 页与 v1.39 tag 语义一致)及 Cluster API v3。
本篇不展开:连接池分池与熔断计数(第 8 篇)、EDS 推送与
warming(第 9–11 篇)、完整 health_checks
字段百科。只回答「名字选中之后,主机集合如何收窄」。
一、Cluster 是什么
在 Envoy 里,Cluster 是上游的逻辑分组:协议选项、LB 策略、熔断阈值、outlier、健康检查、以及(通常经由 EDS)具体 Endpoint 列表,都挂在这一层。Router 只认名字;名字由 RDS 路由或 header 指定,实体由 CDS/静态配置提供。
选主不是一步哈希,而是一层层收窄集合:
flowchart TD
route["Route picks cluster name"] --> pri["Priority levels"]
pri --> loc["Locality / zone-aware"]
loc --> sub["Optional subset by metadata"]
sub --> algo["LB policy picks host"]
algo --> pool["Connection pool to host"]
未配置主动健康检查时,官方 Supported load
balancers 写明:除非另有
health_status,成员默认视为
healthy。被动 outlier 与主动 HC
是另一条轴,见下文入口。
二、Priority:先选「档」,再选主机
EDS 的 LocalityLbEndpoints 可带整数
priority(P=0 最高)。官方 Priority
levels:
- P=0 全健康时,流量全部落在 P=0。
- P=0 变不健康时,流量按 health score 渗漏到更低优先级。
- 默认 overprovisioning factor = 1.4:某档健康主机比例为 \(h\) 时,该档 health score 为 \(\min(100, 1.4 \times 100 \times h)\)(文档以百分比叙述)。
因此约 72% 以上健康时,P=0 仍吃满 100% 流量;50% 健康时约 70% 留在 P=0、30% 到 P=1(假定 P=1 满健康)。文档警告:算法假设「满健康的下一档能接住上一档的全部负载」——若 P=0 有 10 台而 P=1 只有 2 台,这个假设通常不成立。
Normalized total health 低于 100 时,各档份额会按不足总量再归一化,表现为「整集群容量不够时的比例分配」,而不是硬 503(503 更多来自后面无主机 / 熔断)。
三、Locality 与分布式 / 全局 LB
官方 Load balancing overview 区分:
| 类型 | 谁决定权重 | 例子 |
|---|---|---|
| Distributed | 数据面根据观测调整 | 主动 HC、zone-aware routing、LB 算法本身 |
| Global | 控制面下发 priority / locality weight / endpoint weight | EDS 拓扑、金丝雀权重 |
生产上通常两者叠用:控制面画宏观优先级与 locality 权重,Envoy 在档内用 RR / least-request / Maglev 等做微观选择。Zone-aware 可在不显式配 priority 时偏好近端 locality,但有最小主机数等前提;subset 容易打破这些前提,官方 subset 文档单独提醒。
Locality 权重与 priority 渗漏是正交旋钮:priority 决定「流量是否离开 P=0」,locality 决定「在同一 priority 内如何按区分配」。排障时先看 EDS 里主机落在哪一档、哪一 locality,再看 LB 算法——否则会把「整档被抽干」误判成 Maglev 偏向。
四、LB 策略速览(档内)
| 策略 | 要点(v1.39.0 文档) |
|---|---|
| Weighted round robin | 按权重轮转 |
| Least request | 等权时用 P2C(默认抽 2 台比 active requests);不等权时用动态有效权重 |
| Ring hash | Ketama 风格一致哈希;需协议层提供 hash 键 |
| Maglev | 固定表(默认 65537)一致哈希;构建/查找更快,主机变更时扰动通常大于 ring hash |
| Random | 无主动 HC 时往往优于朴素 RR(避免失败主机后的位置偏置) |
Least request 的等权路径引用了 Mitzenmacher 等人关于 power of two choices 的结果:随机抽常数个再取最优,接近全扫描。Maglev 算法来自 Eisenbud 等,NSDI 2016 Maglev: A Fast and Reliable Software Network Load Balancer(Envoy 文档指向论文 §3.4 / §5.3)。环哈希与 Maglev 都要求「有可哈希的请求属性」;否则一致哈希退化。
可插拔 load_balancing_policy(typed
extension)是现行推荐配置面;旧 lb_policy
枚举仍兼容但已走向弃用叙事。
五、Subset:用元数据再切一刀
Subset LB 按 endpoint metadata(必须在
envoy.lb 命名空间)把主机划成子集;路由上的
metadata_match(同样
envoy.lb)精确匹配一个子集后再跑档内算法。
lb_subset_config:
fallback_policy: DEFAULT_SUBSET
default_subset:
stage: prod
subset_selectors:
- keys: [version, stage]
- keys: [stage]| Fallback | 无匹配子集时 |
|---|---|
NO_FALLBACK(默认) |
视同集群无主机 → 请求失败 |
ANY_ENDPOINT |
忽略 metadata,在全集群上 LB |
DEFAULT_SUBSET |
落到配置的默认 metadata 集合 |
主机 metadata 仅在
ClusterLoadAssignment(EDS 或 cluster
load_assignment)路径上受支持。Original
destination 策略与 subset
不兼容。single_host_per_subset
可用于「像一致哈希那样钉死单主机,但主机集合变更时 CPU
更省」的场景。
误配模式:路由带了 version=canary,但
selector 未声明 version 键,或 EDS 未打
metadata → 掉进 fallback;若 fallback 是
NO_FALLBACK,表现就是 no healthy
upstream,而 RDS/CDS「看起来都对」。
加权集群(weighted clusters)上的
metadata_match
会与路由级条件合并,加权侧覆盖同名键。金丝雀常把
stage 写在 weighted cluster 上;只改路由级
metadata 却不改权重项,会出现「以为切了 canary、实际仍匹配
prod 子集」的错觉。
六、健康检查入口(非全书)
| 机制 | 性质 | 本系列位置 |
|---|---|---|
| Active health checking | 主动探活,可改 priority/locality 有效权重 | 配置入口在 Cluster;细节不在本篇展开 |
| Outlier detection | 被动:按失败/延迟等驱逐出 LB 集合 | 第 8 篇 |
| 二者叠加 | 可同时启用;成功主动检查默认可 uneject(可关) | 第 8 篇 |
本篇只需记住:LB
只在「当前健康集合」上选主;主动 HC
改变集合与权重,outlier 从集合中临时摘除主机。未配主动 HC
时不要假设「挂了的进程会被自动踢出」,除非 outlier 或 EDS
health_status 介入。
主动 HC 的配置入口是 Cluster 上的
health_checks(HTTP/TCP/gRPC
等探活)。它改变的是「谁算 healthy /
degraded」,从而喂给上一节的 priority health score
与档内候选集。探活路径、抖动、panic
阈值等属于健康检查专题,本系列只要求读者在排障时把
HC 状态 与 outlier
驱逐、熔断拒请求 分开看。
七、谱系、争论与开放问题
谱系:一致哈希从 Ketama 系环哈希到 Maglev(NSDI 2016)是「变更扰动 vs 查表成本」的经典分叉;P2C(Mitzenmacher 等)支撑 least-request 的等权近似。Envoy 把这些算法嵌进 priority × locality × subset 的多层选择,而不是单一全局哈希环。
争论:Maglev vs ring hash——文档承认 Maglev 更快但主机移除时键迁移约更多;是否可接受取决于会话亲和是否由上层连接跟踪兜底(Maglev 原论文强调 LB 机与后端亲和的运维假设,与 Envoy 进程内表不是同一部署)。
开放问题:控制面全局权重与数据面 zone-aware / subset 同时生效时,最小主机约束与「空子集」故障是否可在配置校验期发现,仍多为运维约定而非协议强制。
八、参考资料
规范 / 官方文档(A)
- Envoy v1.39.0,Supported load balancers、Priority levels、Load balancing overview。
- Envoy 文档树 Load Balancer Subsets(与 Cluster
lb_subset_config/ subset LB policy API 对齐)。 - Envoy API v3
config.cluster.v3.Cluster。
论文(A)
- Eisenbud et al., Maglev: A Fast and Reliable Software Network Load Balancer, NSDI 2016。
- Mitzenmacher 等关于 power of two choices 的负载均衡分析(Envoy least-request 文档回指)。
站内
实验台账
- 本篇无压测;不引用未核对的 Maglev vs ring 迁移百分比仿真细节(文档仅定性 + 官方仿真叙述)。
九、小结
- Cluster 名由 Router 选定;主机选择是 priority → locality → subset → LB 算法的收窄过程。
- Priority 用 overprovisioned health score 渗漏流量;下一档容量不足时数学假设会破功。
- Subset 依赖
envoy.lbmetadata 与 selector 键对齐;错误 fallback 会把「元数据不匹配」伪装成无上游。 - 选中主机之后,连接池、熔断与 outlier 决定是否仍返回 503——见下一篇。
→ 系列目录 · 上一篇:HTTP filter 与 Router · 下一篇:连接池、熔断与 outlier
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Envoy 数据面】Main / Worker 与配置快照:事件循环、TLS 与几乎无锁热路径
钉住 Envoy 单进程多线程模型:Main 管 xDS/Admin,Worker 绑连接终生;Event::Dispatcher 与 Thread Local Storage 如何把配置变成每线程可读快照,以及快照解决什么、解决不了什么。
【Envoy 数据面】Listener 与 FilterChainMatch:accept、listener filters 与选链失败
拆解 Envoy accept 之后到 network filter 之前:listener filters 如何 enrich 元数据,FilterChainMatch 如何按 SNI/ALPN/目的地址选链,以及选错 chain 的典型失败模式。
【Envoy 数据面】Network filter 与 Connection:字节流、水印与 TCP Proxy / HCM 分叉
在 FilterChain 已选定之后,说明 network filter 如何在连接字节流上工作、读写水印如何反压、连接生命周期事件,以及 TCP Proxy 相对 HTTP Connection Manager 的路径分叉。
【Envoy 数据面】HCM 与 Codec:HTTP/1·2·3、流生命周期与编解码错误
说明 HttpConnectionManager 如何把字节变成协议无关的 stream 事件;HTTP/1/2/3 codec 的职责边界;流与连接生命周期差异;以及 codec 错误与半关闭语义的失败模式。