2. 多租户架构基础:多租户定义、租户隔离模型与 Envoy 中的租户标识

2.1 多租户定义与核心概念

多租户(Multi-Tenancy)是一种软件架构模式,允许单个软件实例或集群同时服务多个独立的用户群体(即“租户”)。在云原生和微服务环境中,每个租户通常对应一个业务部门、一个外部客户组织或一个内部项目团队。

多租户架构的核心目标是实现资源复用与逻辑隔离的平衡。与单租户架构相比,多租户能显著降低运维成本和基础设施开销,但必须确保租户之间的数据、流量和性能互不干扰。

关键区分:多租户 ≠ 多用户。多用户指同一系统内有多个账号,但共享同一数据空间和配置;多租户则要求每个租户拥有独立的逻辑或物理边界,包括配置、路由规则、限流策略和可观测性数据。

2.2 租户隔离模型:硬隔离与软隔离

根据隔离的严格程度和实现方式,租户隔离模型主要分为硬隔离和软隔离两大类。下表对比了两种模型的核心差异:

维度 硬隔离(Hard Isolation) 软隔离(Soft Isolation)
资源分配 每个租户独占物理或虚拟资源(独立集群、独立节点) 租户共享同一集群,通过配额和优先级进行资源竞争
故障影响 一个租户的故障不会扩散到其他租户 故障可能通过共享资源池影响其他租户(需流控保护)
性能保障 严格保证,无“吵闹邻居”效应 通过权重、限流和优先级尽力保障
运维成本 高(独立部署、独立升级、独立监控) 低(统一运维、统一升级、统一监控)
适用场景 金融核心、合规敏感、超大规模租户 SaaS 多租户、内部开发环境、中小规模租户

在 Envoy 和 Istio 的实践中,软隔离是更常见的模式。Envoy 通过连接池、HTTP/2 流控、熔断器和限流等机制,在共享数据平面内实现租户间的软隔离。硬隔离则通常通过 Kubernetes 节点亲和性、独立 Sidecar 或独立控制平面来实现。

架构决策提示:选择硬隔离还是软隔离,取决于租户的 SLA 要求和故障容忍度。对于需要严格故障边界的租户(如生产环境 vs 测试环境),建议采用硬隔离;对于需要灵活扩缩容的 SaaS 场景,软隔离配合 Envoy 的精细化流控是更优解。

2.3 Envoy 中的租户标识机制

Envoy 本身不感知“租户”这一业务概念,但提供了多种机制来标识和区分不同租户的流量。这些标识是后续实现流控、路由和故障隔离的基础。

常见的租户标识方式包括:

  • HTTP Header 标识:在请求中插入自定义 Header(如 X-Tenant-ID),Envoy 通过 header_matcher 或 metadata 动态路由。
  • JWT Claim 标识:从 JWT 的 sub、iss 或自定义 Claim 中提取租户信息。
  • 源 IP/子网标识:根据请求来源 IP 或 CIDR 范围划分租户。
  • gRPC Metadata:在 gRPC 请求的 Metadata 中携带租户上下文。

以下是一个典型的 Envoy 动态转发配置片段,展示如何根据 X-Tenant-ID Header 将流量路由到不同的上游集群:

static_resources:
  listeners:
  - name: ingress_listener
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }
    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: tenant_routes
            virtual_hosts:
            - name: tenant_a
              domains: ["*"]
              routes:
              - match:
                  headers:
                  - name: X-Tenant-ID
                    string_match: { exact: "tenant-alpha" }
                route:
                  cluster: tenant_alpha_cluster
            - name: tenant_b
              domains: ["*"]
              routes:
              - match:
                  headers:
                  - name: X-Tenant-ID
                    string_match: { exact: "tenant-beta" }
                route:
                  cluster: tenant_beta_cluster
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

下图展示了 Envoy 中基于 Header 的租户标识与路由流程:

Envoy 租户标识与路由流程 客户端 A 客户端 B Envoy Proxy Header 匹配引擎 tenant-alpha 上游集群 tenant-beta 上游集群 X-Tenant-ID: tenant-alpha X-Tenant-ID: tenant-beta 租户标识关键点 • 标识位置:HTTP Header / JWT Claim / gRPC Metadata / 源 IP • 标识粒度:租户级、用户级、应用级均可 • 标识传递:需在入口网关或 Sidecar 处提取并注入到请求上下文

2.4 租户标识的最佳实践

在实际部署中,租户标识的选取直接影响流控策略的准确性和可维护性。以下是几条经过验证的实践原则:

  • 标准化标识名称:在整个网格内统一使用 X-Tenant-ID 或 X-Org-ID 等标准 Header,避免不同服务使用不同命名。
  • 标识不可伪造:在入口网关处验证 JWT 签名或从可信的认证服务中获取租户信息,防止客户端伪造租户标识绕过隔离策略。
  • 标识与元数据绑定:将租户标识与 Envoy 的 metadata 动态元数据绑定,便于在限流、熔断和可观测性中引用。
  • 考虑嵌套租户:对于大型组织,可能需要支持“租户组”或“子租户”层级,此时标识应包含层级信息(如 X-Tenant-ID: org:dept:team)。
常见陷阱:不要仅依赖请求路径(如 /tenant-a/api/)来标识租户。路径容易因路由重写或 API 版本升级而改变,且难以在 gRPC 等非 HTTP/1.x 协议中统一处理。优先使用 Header 或 JWT Claim 作为稳定的标识载体。

下图展示了在 Istio/Envoy 网格中,租户标识从入口网关到 Sidecar 再到上游服务的完整传递链路:

租户标识在网格中的传递链路 外部客户端 入口网关 Sidecar Proxy 上游服务 标识传递步骤 ① 外部客户端携带 JWT 或 Header 请求入口网关 ② 入口网关验证 JWT 签名,提取租户 ID 并注入到 X-Tenant-ID Header ③ Sidecar 根据 X-Tenant-ID 选择限流/熔断策略,并转发给上游服务 ④ 上游服务从 Header 中读取租户 ID,进行业务逻辑隔离

2.5 本章小结