服务网格 11:负载均衡为何不等于平均分请求
两个库存 Pod 都健康,为何一个更忙
先区分问的是外部请求数、代理选择次数、上游新连接数,还是库存实际处理次数。第 10 篇的 50/50 权重是路由目标,不能从 10 次样本推断每台必处理 5 次。即使 v1/v2 都在候选列表,长连接、HTTP/2 复用、端点权重、请求耗时、健康状态和 locality 优先级都会改变计数;有重试时一次用户请求可能对应多次后端尝试。
对于请求从 orders 到 inventory 的路径,可能先经过 Kubernetes Service 的连接级目标选择,再经过网格代理的 cluster 选址,具体取决于实际透明接管及协议模式。不能把某一个实现的“轮询”机械地套用到每个 HTTP 请求:先拿到相关 listener/route/cluster 的活跃配置及连接/请求日志,再确定正在讨论哪一层的选址。
选择时刻决定了统计含义
客户端只维持一条被 Service 转发到旧 Pod 的 TCP 连接时,后续复用该连接的请求可能持续命中旧实例;扩容引入新实例主要影响后续新建连接。Envoy 对其上游 cluster 的具体负载均衡与连接池调度另有策略,可能按请求选择可用 host,也可能受优先级、权重与健康集合约束;不能仅凭应用连接的长期后端不变,反推 Envoy 的负载均衡算法。
在 HTTP/2 中,一个 TCP 连接可同时承载多个流,不等于一个请求对应一条独立连接;逐条记录 downstream connection、upstream host、请求 ID 和库存版本,才能区分“连接固定后端”与“代理对请求逐次选 host”。并发不同步时,先完成的请求并不一定代表先分配的请求;将最终响应顺序当作选址顺序会产生误判。
健康和局部性还会改变候选集合:EndpointSlice readiness、Envoy 主动健康检查、被动异常摘除、locality 规则和 failover 是不同机制,具体是否启用要读取发布版本与活跃配置。把不健康 v2 排除后,仍宣称“请求必须平均分到 v1/v2”没有意义;如果两个故障域的实例配置了非对称权重,简单计数也不能反推故障。
直达 inventory 的两组 200 请求
工程的 mainline/11/sample.sh 在 frontend 容器里启动 loadgen,但目标直接设为 http://inventory:8080。这跳过 frontend 和 orders 的 handler,避免把 frontend 连接复用误当成 orders 的连接池变化。先用第 02 篇 bare 集群,确认没有遗留路由,运行:
1 | |
第一组 -requests 200 -reuse=true 串行读取响应,第二组 -reuse=false 禁用该客户端 HTTP keep-alive;每组 ID 从 sm-11-true-0 或 sm-11-false-0 递增。两个库存 Deployment 各 1 副本,Service 选择 app=inventory。这里测的是同一客户端实现下两种连接策略,不是吞吐压测。
analyze.mjs 要求每组恰有 200 行、ID 唯一且连续、版本只包含 v1/v2,随后输出 counts、v2Fraction 和相邻响应版本切换次数 transitions。例如一个明确标注为演算的序列 v1、v1、v2、v2 有一次版本切换;它不能证明只建立了两条 TCP 连接。真实分布只读取本次 analysis.json,不预设各 100 次。
在 sidecar 集群复跑时,请求先由客户端代理解析,可能按请求选择后端。即使应用复用一个下游连接,代理也可能在两个后端之间分配请求。保存代理 route/cluster/endpoint 与 upstream_host 后才能解释差异;该脚本保存的应用版本计数不等于 socket 数。
故障扩展可在专用集群将 inventory-v2 缩到 0,等待 Pod 删除,另用新证据目录复跑;新采样应只包含存活版本。随后恢复 1 副本,等待 available,再采样。这个扩展不保留故障前 socket,不能证明旧连接迁移。当前集群采样 NOT_RUN;分析器的合成样本测试只验证计数与拒绝残缺输入。
[PATTERN] 连接池改变选择次数,代理又引入独立上游池;负载均衡结论必须注明在哪一跳、按什么单位计数。
| 原则 | 本实验的约束 |
|---|---|
| 控制变量在正确链路 | loadgen 直接访问 inventory |
| 成功标准不强求平均 | 检查完整性,记录实际分布 |
| 观测单位可审计 | 响应版本变化不冒充连接变化 |
练习与参考解答
- 两个 endpoint 均列在快照里,一分钟内应用日志却是 v1:900、v2:100。是否证明权重写成了 90:10?参考解答:不能。先核对快照时间、健康和优先级、真实活跃权重、客户端连接复用与请求数,以及重试/失败的统计分母;应用处理次数不等于代理初次选 host 次数。时间窗口不同还可能产生错位。
- 不改权重,只把一个库存 Pod 标为 not ready,怎样构造能证伪“旧连接立即迁移”的实验?参考解答:在只针对合成实例的隔离集群保留到该 Pod 的旧连接,并开一批新连接;逐请求保存客户端 socket、EndpointSlice 条件、代理 endpoint 状态与后端 ID。若旧连接仍完成在途处理而新连接避开该实例,就能否定“端点变化必立即迁移所有连接”;实际结果需运行后填写。
官方资料与系列导航
- Envoy v1.37.0 负载均衡 与 健康检查:选择、健康集合与可观测状态。
- Istio locality load balancing:地域和故障域作用,实际字段须与冻结 Istio 版核对。
- Kubernetes EndpointSlice:后端集合与条件,不保证旧连接重分配。
系列导航:00 基线 → 10 版本与请求属性 → 11 负载均衡与连接复用(本文)→ 12 Gateway API 网格路由。
