2. Envoy架构基础:Listener、Cluster、Endpoint、Filter链,以及多租户配置的入口设计

在构建多租户故障域之前,必须深入理解Envoy的核心抽象层。Envoy的架构围绕四个基本概念展开:Listener(监听器)、Cluster(集群)、Endpoint(端点)和Filter链(过滤器链)。多租户隔离的入口设计正是建立在这些基础组件之上的策略性组合。

2.1 核心抽象层概述

Envoy采用分层架构,每一层负责不同的职责。下表总结了四个核心概念及其在多租户场景中的角色:

概念 职责 多租户关键属性
Listener 监听端口,接收入站连接 绑定IP/端口、TLS证书、Filter链入口
Filter链 处理请求/响应的管道 租户识别、认证、限流、路由决策
Cluster 定义上游服务组 连接池、断路器、负载均衡策略
Endpoint 上游服务实例 健康检查、权重、故障域标签
关键理解:在多租户架构中,Listener是租户流量的第一道隔离边界。通过为每个租户分配独立的Listener或使用Filter链进行租户分流,可以实现流量的逻辑隔离。

2.2 Listener:流量的入口边界

Listener是Envoy接收外部流量的起点。每个Listener绑定到一个或多个IP地址和端口。在多租户场景中,Listener的设计直接决定了租户隔离的粒度。

  • 独占Listener模式:每个租户绑定独立的IP:Port组合,物理隔离,配置简单但端口消耗大。
  • 共享Listener模式:所有租户共享同一个IP:Port,通过Filter链中的filter_chain_match(如SNI、HTTP Host header)进行租户路由。
  • 混合模式:关键租户使用独占Listener,普通租户共享Listener。
# 共享Listener示例:通过TLS SNI区分租户
listeners:
- name: shared_ingress
  address:
    socket_address: { address: 0.0.0.0, port_value: 443 }
  filter_chains:
  - filter_chain_match:
      server_names: ["tenant-a.example.com"]
    filters: [ ... ]  # 租户A的Filter链
  - filter_chain_match:
      server_names: ["tenant-b.example.com"]
    filters: [ ... ]  # 租户B的Filter链

2.3 Filter链:请求处理的管道

Filter链是Envoy最灵活的扩展点。每个Listener或Listener Filter Chain可以关联一组L4/L7过滤器。这些过滤器按顺序执行,形成请求处理管道。

在多租户架构中,Filter链通常包含以下关键阶段:

  1. 租户识别:通过TLS SNI、HTTP Host header、JWT 等识别租户身份。
  2. 认证与授权:验证租户凭证,检查访问权限。
  3. 租户级限流:基于租户ID进行速率限制,防止单个租户耗尽资源。
  4. 路由决策:根据租户ID将请求路由到对应的Cluster。
  5. 故障注入与观测:注入延迟/错误,收集租户级指标。
注意:Filter链的顺序至关重要。租户识别过滤器必须位于认证和路由过滤器之前,否则后续过滤器无法获取租户上下文。

2.4 Cluster与Endpoint:上游服务抽象

Cluster定义了一组提供相同服务的上游主机。Endpoint是Cluster中的具体服务实例。在多租户环境中,Cluster的设计直接影响故障隔离范围。

  • 租户独占Cluster:每个租户拥有独立的Cluster,资源完全隔离,故障域最小。
  • 共享Cluster + 租户标签:多个租户共享同一个Cluster,通过Endpoint的元数据标签(如tenant_id)进行路由。
  • 混合Cluster策略:核心服务使用独占Cluster,非核心服务共享Cluster。
# 租户独占Cluster配置示例
clusters:
- name: tenant_a_service_cluster
  connect_timeout: 0.25s
  type: STRICT_DNS
  lb_policy: ROUND_ROBIN
  endpoints:
  - lb_endpoints:
    - endpoint:
        address:
          socket_address: { address: 10.0.1.10, port_value: 8080 }
    - endpoint:
        address:
          socket_address: { address: 10.0.1.11, port_value: 8080 }

- name: tenant_b_service_cluster
  connect_timeout: 0.25s
  type: STRICT_DNS
  lb_policy: ROUND_ROBIN
  endpoints:
  - lb_endpoints:
    - endpoint:
        address:
          socket_address: { address: 10.0.2.10, port_value: 8080 }

2.5 多租户入口设计模式

基于上述核心组件,多租户入口设计通常采用以下模式。下图展示了两种典型架构的对比:

多租户入口设计模式对比 独占Listener模式 Listener A 10.0.0.1:443 Listener B 10.0.0.2:443 Filter链 A TLS → Auth → Route → Limit → Fault Filter链 B TLS → Auth → Route → Limit → Fault Cluster A 独占资源池 Cluster B 独占资源池 优点:强隔离,故障域最小 缺点:端口/资源消耗大 适用:关键租户、合规要求高 共享Listener模式 共享 Listener 0.0.0.0:443 (SNI分流) Filter Chain Match SNI: tenant-a.example.com → 链A SNI: tenant-b.example.com → 链B Filter链 A Filter链 B 优点:端口节省,灵活扩展 缺点:Filter链复杂度高 适用:SaaS平台、多租户共享入口

2.6 多租户配置入口设计原则

基于上述架构分析,多租户入口设计应遵循以下原则:

设计原则清单:
  • 隔离优先:关键租户使用独占Listener + 独占Cluster,实现物理级隔离。
  • Filter链标准化:所有租户共享相同的Filter链模板,通过配置参数(如租户ID)差异化行为。
  • 租户上下文传递:在Filter链早期阶段将租户ID注入请求头或动态元数据,供后续过滤器使用。
  • 资源配额前置:在Listener或Filter链入口处实施租户级连接数和请求速率限制,防止“吵闹邻居”效应。
  • 可观测性标签:所有指标和日志必须携带租户ID标签,支持按租户维度进行故障定位。

2.7 入口配置的故障域影响

入口设计直接决定了故障域的边界。下表总结了不同设计选择对故障域的影响:

设计选择 故障域范围 恢复复杂度 资源效率
独占Listener + 独占Cluster 单个租户 低(重启单个Listener) 低
共享Listener + 独占Cluster 单个租户(Cluster级) 中(需隔离Cluster) 中
共享Listener + 共享Cluster 多个租户 高(需全局恢复) 高
混合模式(关键租户独占) 按租户等级分层 中(分级恢复) 中高
实践建议:在生产环境中,推荐采用混合模式。为SLA要求高的租户分配独占Listener和Cluster,为普通租户使用共享Listener + 基于租户标签的Cluster路由。这样可以在资源效率和故障隔离之间取得平衡。