4. 基于Header的流量路由:配置Route匹配规则,实现租户A/B流量分发

在多租户架构中,Envoy 通过 Header 路由 实现租户级别的流量隔离与分发。本节将深入讲解如何基于 HTTP Header 中的租户标识(如 x-tenant-id)配置 Route 匹配规则,将流量精准路由至对应的后端集群,并演示 A/B 租户的流量分发策略。

4.1 核心概念:Header 路由与租户标识

Envoy 的 RouteConfiguration 支持基于 请求 Header 的匹配规则。在多租户场景中,通常由网关或客户端在请求中注入租户标识 Header,Envoy 根据该 Header 的值选择对应的路由集群。

概念 说明 典型 Header 示例
租户标识 Header 用于区分不同租户的 HTTP Header,通常由上游网关或客户端 SDK 注入 x-tenant-id: tenant-a
Header 匹配规则 Envoy 在 RouteMatch 中定义的 headers 字段,支持精确匹配、正则匹配、范围匹配等 name: x-tenant-id
exact_match: "tenant-a"
虚拟主机 (VirtualHost) 一组路由规则的集合,通常对应一个域名或一组域名 domains: ["*"]
集群 (Cluster) 后端服务的端点集合,每个租户可对应独立的集群 cluster: tenant-a-backend
最佳实践: 建议使用 x-tenant-id 作为标准租户标识 Header,避免使用 Host 或 Authorization 等标准 Header 承载租户信息,以保持语义清晰且不干扰其他中间件处理。

4.2 配置示例:基于 Header 的租户 A/B 路由

以下是一个完整的 Envoy 静态配置片段,演示如何根据 x-tenant-id 将流量分发到 租户 A 和 租户 B 的后端集群。

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 10000 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: tenant_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                  headers:
                  - name: x-tenant-id
                    exact_match: "tenant-a"
                route:
                  cluster: tenant_a_cluster
              - match:
                  prefix: "/"
                  headers:
                  - name: x-tenant-id
                    exact_match: "tenant-b"
                route:
                  cluster: tenant_b_cluster
              - match:
                  prefix: "/"
                route:
                  cluster: default_cluster
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
  - name: tenant_a_cluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: tenant_a_cluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: tenant-a-backend, port_value: 8080 }
  - name: tenant_b_cluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: tenant_b_cluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: tenant-b-backend, port_value: 8080 }
  - name: default_cluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: default_cluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: default-backend, port_value: 8080 }
配置要点解析:
  • 路由优先级: Envoy 按配置顺序匹配路由,因此租户 A/B 的精确匹配规则应放在默认路由之前。
  • 默认路由: 当请求未携带 x-tenant-id 或值不匹配时,流量落入 default_cluster,可作为兜底或灰度策略。
  • 集群隔离: 每个租户拥有独立的集群,可实现资源隔离与故障域隔离。

4.3 流量分发流程:Header 路由决策图

下图展示了 Envoy 接收到请求后,基于 x-tenant-id Header 进行路由决策的完整流程。

基于Header的租户A/B流量路由流程 基于 x-tenant-id Header 的租户 A/B 路由决策流程 客户端请求 RouteMatch: headers 匹配 检查 x-tenant-id 值 exact_match: "tenant-a" exact_match: "tenant-b" 默认匹配 (无Header) 租户A集群 (tenant-a) 租户B集群 (tenant-b) 默认集群 (default) tenant-a-backend:8080 tenant-b-backend:8080 default-backend:8080 💡 路由优先级:精确匹配(tenant-a/tenant-b) > 默认匹配。未携带 x-tenant-id 的请求将路由至默认集群。 每个租户集群独立部署,实现故障隔离与资源隔离。

4.4 高级匹配规则:正则与范围匹配

除了精确匹配,Envoy 还支持 正则匹配 和 范围匹配,适用于更复杂的租户标识场景,例如租户 ID 包含版本号或环境标识。

匹配类型 配置字段 示例 适用场景
精确匹配 exact_match exact_match: "tenant-a" 租户标识固定不变
正则匹配 safe_regex_match safe_regex_match: { regex: "tenant-[a-z]+" } 租户 ID 包含动态后缀(如环境、版本)
范围匹配 range_match range_match: { start: 100, end: 200 } 租户 ID 为数字范围,用于灰度或分桶
前缀匹配 prefix_match prefix_match: "tenant-" 租户标识具有统一前缀
存在匹配 present_match present_match: true 仅检查 Header 是否存在,不关心值
注意: 正则匹配使用 safe_regex_match 而非 regex_match,以避免 ReDoS 攻击。建议在生产环境中对正则表达式进行性能测试。

4.5 多 Header 组合匹配与权重路由

Envoy 支持在一条路由规则中组合多个 Header 条件,实现更精细的流量控制。同时,结合 权重路由 (Weighted Clusters),可以实现租户内部的 A/B 测试或灰度发布。

routes:
- match:
    prefix: "/"
    headers:
    - name: x-tenant-id
      exact_match: "tenant-a"
    - name: x-env
      exact_match: "staging"
  route:
    weighted_clusters:
      clusters:
      - name: tenant_a_v1
        weight: 90
      - name: tenant_a_v2
        weight: 10
组合匹配效果: 只有当请求同时携带 x-tenant-id: tenant-a 和 x-env: staging 时,才会匹配该路由,并将 90% 流量导向 v1 版本,10% 导向 v2 版本。这为多租户场景下的灰度发布提供了灵活的控制能力。

4.6 验证与调试

配置完成后,可通过 curl 命令验证 Header 路由是否生效:

# 请求租户A
curl -H "x-tenant-id: tenant-a" http://localhost:10000/api/v1/resource

# 请求租户B
curl -H "x-tenant-id: tenant-b" http://localhost:10000/api/v1/resource

# 请求默认路由(不携带Header)
curl http://localhost:10000/api/v1/resource

通过 Envoy 的 Admin 接口 查看路由统计和集群状态:

# 查看路由配置
curl http://localhost:9901/config_dump

# 查看集群统计
curl http://localhost:9901/clusters
调试建议: 在开发环境中,可以在 Envoy 配置中开启 access_log,记录每个请求的 Header 信息和路由决策,便于快速定位路由问题。