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链通常包含以下关键阶段:
- 租户识别:通过TLS SNI、HTTP Host header、JWT 等识别租户身份。
- 认证与授权:验证租户凭证,检查访问权限。
- 租户级限流:基于租户ID进行速率限制,防止单个租户耗尽资源。
- 路由决策:根据租户ID将请求路由到对应的Cluster。
- 故障注入与观测:注入延迟/错误,收集租户级指标。
注意: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 多租户入口设计模式
基于上述核心组件,多租户入口设计通常采用以下模式。下图展示了两种典型架构的对比:
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路由。这样可以在资源效率和故障隔离之间取得平衡。