VirtualService 基于 Header 分流

解读

在国内 PHP 面试中,提到 VirtualService 通常不是考 PHP 语法,而是考“PHP 工程师在微服务/云原生场景下如何与 Istio 配合做灰度发布、A/B 测试”。
面试官想确认三件事:

  1. 你知道 Istio 的 VirtualService 资源长什么样;
  2. 你知道如何用 HTTP Header 做条件匹配;
  3. 你能把这条规则落地到 PHP 业务里——让 PHP 代码无侵入地参与灰度,而不是“我只会写 YAML”。
    因此,回答要同时给出 YAML 示例、PHP 侧配合方式、以及国内大厂常用的“染色”套路(如把 uid 写在 Header 里,再透传给下游)。

知识点

  1. Istio VirtualService 语法:http.match.headers 支持 exact、regex、prefix。
  2. 分流优先级:match 数组自上而下,第一个命中即停止。
  3. PHP 侧染色:
    • 入口网关(Nginx/OpenResty)统一加 X-Gray-Version;
    • 业务代码用 $_SERVER['HTTP_X_GRAY_VERSION'] 识别灰度环境;
    • 向下游发请求时把 Header 继续带出去(Guzzle/Curl 设置 CURLOPT_HTTPHEADER)。
  4. 国内灰度常见字段:X-Gray、X-Canary、X-Uid-Hash(uid 取模)。
  5. 灰度数据一致性:MySQL 影子表、Redis 影子 key、RocketMQ 影子 topic。
  6. 回滚策略:VirtualService 权重瞬间改 0,或直接把 match 条件注释掉,kubectl apply -f 平均 3 秒生效。
  7. 性能注意:Header 匹配在 Envoy 侧做,不占 PHP CPU,但 Header 过多会增加网络带宽,建议只保留 1~2 个灰度标识。

答案

“我上一个电商项目用 Istio 做灰度,核心就是 VirtualService 按 Header 分流,PHP 代码零侵入。
YAML 片段如下:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: php-api-vs
namespace: shop
spec:
hosts:

  • api.shop.com
    http:
  • match:
    • headers:
      X-Gray:
      exact: "v2"
      route:
    • destination:
      host: php-api
      subset: v2
      weight: 100
  • route:
    • destination:
      host: php-api
      subset: v1
      weight: 100

线上流程:

  1. 运维先把 v2 镜像跑成 Deployment,贴上 version=v2 标签,对应 DestinationRule 里建一个叫 v2 的 subset。
  2. 测试通过后,产品在 PHP 入口埋点:
    if (isset(_GET['_gv']) && _GET['_gv']==='v2') {
    header('X-Gray: v2');
    }
    这样测试同学只要在 URL 后拼 ?_gv=v2 就能进灰度。
  3. 逐步放量时,把 match 条件改成 headers.X-Uid-Hash.regex: "^[0-3].*" ,表示 uid 哈希 0~3 的用户进 v2;PHP 把 uid 取模后写入 X-Uid-Hash,再带出去。
  4. 如果出问题,3 秒内把 weight 直接改 0 或 kubectl delete vs,流量瞬间回到 v1,PHP 无感。

整个方案让 PHP 只负责‘染色’,不碰路由,符合国内大厂‘业务只写业务,基础设施下沉’的规范。”

拓展思考

  1. 多环境并行:测试、预发、灰度、生产四个环境共用同一套 PHP 镜像,只靠 Header 区分,如何防止配置漂移?
    答:把环境标识写进 ConfigMap,PHP 启动时读 $_ENV['ENV_TAG'],再决定连哪组 DB/Redis,保证“同镜像不同配置”。
  2. 链路级别染色:订单服务灰度 10%,库存服务必须也走灰度,否则数据不一致。
    答:在 Istio 1.16+ 用 TrafficLabel + RequestAuthentication,把首次灰度 Header 注入 Baggage,下游所有 PHP 微服务通过 OpenTelemetry 自动透传,实现“全链路灰度”。
  3. 性能压测:Header 匹配会不会成为瓶颈?
    答:Envoy 使用 radix tree 匹配,单核 40 万 RPS 内无感知;但国内双 11 峰值常破 100 万,此时可把灰度规则下放到 Nginx+Lua,减少一跳 Envoy,PHP 仍无感。