Envoy 架构:Listener、Cluster 与 Filter Chain
一个请求究竟是如何在 Envoy 中流转的,从它到达的套接字,到被转发的上游。
Envoy 的设计直接源于它最初的目标:让网络对应用透明,并让区分网络问题与应用问题变得快速。这一目标塑造了词汇 —— listener、cluster、filter —— Envoy 的每一份配置都由它们构建。本指南介绍每一个的作用,以及请求如何在它们之间流转。
下游与上游
Envoy 把向它发送请求的一方称为下游(downstream),把它转发请求的目的地称为上游(upstream)。下游可以是终端用户的浏览器、网格中的另一个服务,或任何向 Envoy 打开连接的东西。上游是 Envoy 决定路由到的地方:一个应用实例、另一个服务、一个外部 API。Envoy 中的每一份配置都位于这条线的某一侧。
Listener:连接进入的地方
Listener 绑定到一个端口并接受其上的连接。单个 Envoy 实例可以定义多个 listener,每个都有自己的端口和自己的处理管线,因此一个实例可以,例如,在 443 上终止 TLS,同时用完全不同的规则处理 8080 上的明文流量。listener 在对连接进行路由之前所需要做的一切 —— TLS 终止、协议检测等等 —— 都通过附加在它上面的过滤器完成,本系列的下一篇指南会深入介绍。
Cluster:连接去往的地方
Cluster 是 Envoy 可以将流量路由到的一个或多个上游端点所组成的、具名的逻辑分组。如果你来自 Kubernetes,有一个类比很容易理解:cluster 大致相当于 Service,而其中的各个端点大致相当于其背后的 Pod。Envoy 跟踪每个端点的健康状态,应用 cluster 所配置的负载均衡策略,并在健康的端点中为每个请求挑选一个目标。
Filter 与 filter chain
listener 接受连接之后,数据会流过一系列过滤器(filter),它们是小而专注的单元,各自只做一件事,串联成一个 filter chain。最基本的过滤器工作在网络层(TCP 或 UDP),处理原始字节流,此时尚未有任何内容被解析为更高层的协议。Envoy 开箱即带有用于 MongoDB、Redis 和 Kafka 等协议处理的网络过滤器。
对于 HTTP 流量,有一个特定的网络过滤器承担了大部分重活:HTTP Connection Manager,它将原始字节解析为 HTTP 请求、头和主体,并暴露出它自己的嵌套 HTTP 级过滤器链 —— 访问日志、重试、头部操作等等 —— 它们在流量成为 HTTP 而不只是字节之后才工作。本系列的下一篇指南完全专注于它。
Route:选择 cluster
流量到达 HTTP 层之后,**路由(route)**会根据请求本身的特征 —— 主机、路径、头部 —— 决定该请求去往哪个 cluster。对 example.com/api 的请求可能匹配一条把它发往 example-com cluster 的路由,而不同的主机或路径则匹配另一条完全不同的路由。路由匹配把”某个 HTTP 请求到达了”变成了”这是它所属的具体 cluster”。
整合起来:请求的路径
downstream client
│
▼
listener (bound to a port)
│
▼
filter chain (network filters, then HTTP Connection Manager)
│
▼
route matching (host, path, headers)
│
▼
cluster (a named group of endpoints)
│
▼
load balancing + health checking
│
▼
upstream endpoint
请求到达 listener,流过该 listener 的 filter chain,被路由规则匹配到一个 cluster,然后 Envoy 的 cluster 管理器在该 cluster 内挑选一个健康的端点来实际发送。Envoy 所做的一切 —— TLS、限流、重试、可观测性 —— 都附着在这些阶段之一,而不是作为独立的关注点存在,这恰恰是该项目最初设定的”网络是透明的、问题易于定位”的设计:因为每个阶段都是显式且可检查的,缓慢的响应或失败的请求通常可以追溯到某个具体的 listener、过滤器或 cluster,而不需要靠猜测。
关于每个阶段究竟发生了什么,有更详细的说明,包括本指南有意简化的那部分架构(工作线程、连接池),可参阅 Envoy 自己的”请求的一生”文档,它会逐步讲解完整的内部流程。