“10% 给 v2”是路由意图,还是已发生的调用比例

同一服务链中的 inventory-v1、inventory-v2 返回各自版本标识;第 06 篇已拆开规则声明与代理执行。现在发布 v2:先让带 x-canary: yes 的合成请求稳定到 v2,再测试不带头时按权重选择 v1/v2。Subset 属于后端实例分类,匹配条件属于请求分类,权重属于某条 route 下的目标比例;三者不能写成一项配置。读者应能区分提交的权重、代理选择次数、后端处理次数与最终客户端成功次数。

先按请求头选择 canary 路由,再按权重选择 subset,由后端版本和请求标识核验

图的第一步是请求匹配:若顺序靠前的规则匹配 canary 头,就不再按照后续默认权重规则选择;否则才进入默认路由。v1/v2 subset 必须与实际工作负载的版本标签一致,而不是只看 Deployment 名或镜像 tag。

路由规则、端点与观测单位

在 Istio 风格的配置中,DestinationRule 可给 inventory 定义 v1/v2 标签集合,VirtualService 可按 URI/请求头选目标及配置权重。只有当请求的 host、端口、header 落在相应 VirtualService 作用域内,且目标 subset 有实际可用 endpoint,代理才可能按意图执行;对象都存在不等于当前代理路由已切换。检查第 06–07 篇的资源提交、控制器处理、代理活跃 route/cluster/endpoint,再检查访问日志与库存应用的相同请求 ID。

权重不是“每十个请求必有一个 v2”。如果用独立同分布的简化模型,令选 v2 概率为 0.1,发送 20 次请求,则期望 v2 为 2 次,标准差为 sqrt(20 × 0.1 × 0.9) ≈ 1.34,恰好 0 次的概率为 0.9^20 ≈ 0.122。这些数是理论示意,不是本仓库压测结果,也不是对 Envoy 的具体实现保证。连接复用、负载均衡策略、重试、统计窗口和多个代理各自的采样都会改变可观察的计数。若代理对一个用户请求重试两次,后端看到的尝试数可能超过外部请求数,不能用两种分母计算同一个“灰度百分比”。

优先用显式头路由核对机制,再在固定采样数量、连接复用方式和无重试的条件下检验权重近似值。客户端应为每个用户请求生成不同 ID;后端日志、代理 attempt 记录、响应版本和账本要保持关联,防止读请求与将来的扣减请求混作同一安全场景。代理的权重选择不能保护非幂等写入的业务语义。

先验证确定路由,再统计权重

从 examples/service-mesh/ 运行 SM_CONTEXT=kind-service-mesh-sidecar bash scripts/cluster-case.sh 10。使用第 06 篇同一份 inventory-route.yaml:精确头 yes 到 v2、无头到 v1、错误 subset 失败、恢复标签后再到 v2。这四个判据先检验目标选择链,不能用一次随机样本代替。

权重扩展单独进行:确认没有其他同名实验规则后,应用原清单,再只替换默认规则的 route 数组。以下命令保持第一条 canary 匹配不变:

1
2
3
kubectl --context kind-service-mesh-sidecar apply -f deploy/kubernetes/inventory-route.yaml
kubectl --context kind-service-mesh-sidecar -n service-mesh-lab patch virtualservice inventory --type=json -p '[{"op":"replace","path":"/spec/http/1/route","value":[{"destination":{"host":"inventory.service-mesh-lab.svc.cluster.local","subset":"v1","port":{"number":8080}},"weight":90},{"destination":{"host":"inventory.service-mesh-lab.svc.cluster.local","subset":"v2","port":{"number":8080}},"weight":10}]}]'
kubectl --context kind-service-mesh-sidecar -n service-mesh-lab exec deploy/frontend -c app -- /mesh-demo -role loadgen -frontend-url http://frontend:8080 -requests 1000 -reuse=true -request-id sm-10-weight > weight.jsonl

每行成功响应带唯一 ID 和 inventory_version;统计 v2 行数除以成功行数,并另外保留失败退出码、请求总数 1000 与代理访问记录。若中途失败,loadgen 会退出,不能把剩余行仍称为 1000 请求成功样本。此处 reuse 控制的是 loadgen 到 frontend,orders 的连接池是另一段。

恢复确定路由用 kubectl --context kind-service-mesh-sidecar apply -f deploy/kubernetes/inventory-route.yaml,再次发送 canary 与无头请求。实验结束后删除本次创建的 VirtualService 和 DestinationRule,确保第 12 篇没有竞争规则。当前集群及权重采样均 NOT_RUN,没有预填 v2 百分比。

[PATTERN] 策略选择分为请求分类、版本分类、目标权重;分开修改可以定位到底是哪一维失效。

原则 检验点
确定性验证先行 头路由先确认两个版本可达
分母显式 请求、成功、尝试分别计数
统计不替代状态检查 活跃路由与样本一起保存

练习与参考解答

  1. 配置 10% 给 v2,20 次调用均到 v1,是否直接判断配置错误?参考解答:不能。按上述独立概率示意,0 次 v2 有约 12.2% 的概率;先核对实际规则、代理当前路由、样本是否经过该代理以及后端请求 ID,再增大样本量并固定连接和重试条件。真实代理算法与相关性还要单独检验。
  2. 保持请求头与权重不变,只把 v2 subset 标签改成 Pod 不具备的标签,会先在哪层暴露?参考解答:API 可能接受语法合法的规则,但对应代理的 cluster/endpoint 缺目标实例;也可能被特定实现提前诊断。必须保存对象状态、当前代理资源及带头请求的失败位置,不能猜一个固定 HTTP 码;若看到请求仍成功到 v2,应先查是否命中了另一条路由。

官方资料与系列导航

系列导航:00 基线 → 09 协议与 TLS → 10 按版本和请求属性选择后端(本文)→ 11 负载均衡与连接复用。