Envoy
Envoy 是一款由 Lyft 开源的高性能数据和服务代理软件,使用现代 C++ 开发,提供四层和七层网络代理能力。尽管在设计之初 Envoy 没有将性能作为最终的目标,而是更加强调模块化、易测试、易开发等特性,可它仍旧拥有足可媲美 Nginx 等经典代理软件的超高性能。在保证性能的同时,Envoy 也提供了强大的流量治理能力和可观察性。其独创的 xDS 协议则成为了构建 Service Mesh 通用数据面 API(UPDA)的基石。
Architecture
首先介绍 Envoy 中的一些基本概念:
- Downstream:下游主机,指连接到 Envoy 的主机,这些主机用来发送请求并接受响应。
- Upstream:上游主机,指接收来自 Envoy 连接和请求的主机,并返回响应。
- Listener:服务或程序的监听器, Envoy 暴露一个或多个监听器监听下游主机的请求,当监听到请求时,通过 Filter Chain 把对请求的处理全部抽象为 Filter, 例如 ReadFilter、WriteFilter、HttpFilter 等。
- Cluster:服务提供集群,指 Envoy 连接的一组逻辑相同的上游主机。Envoy 通过服务发现功能来发现集群内的成员,通过负载均衡功能将流量路由到集群的各个成员。
- xDS:xDS 中的 x 是一个代词,类似云计算里的 XaaS 可以指代 IaaS、PaaS、SaaS 等。DS 为 Discovery Service,即发现服务的意思。xDS 包括 CDS(cluster discovery service)、RDS(route discovery service)、EDS(endpoint discovery service)、ADS(aggregated discovery service),其中 ADS 称为聚合的发现服务,是对 CDS、RDS、LDS、EDS 服务的统一封装,解决 CDS、RDS、LDS、EDS 信息更新顺序依赖的问题,从而保证以一定的顺序同步各类配置信息。以上 Endpoint、Cluster、Route 的概念介绍如下:
- Endpoint:一个具体的“应用实例”,类似于 Kubernetes 中的一个 Pod;
- Cluster:可以理解“应用集群”,对应提供相同服务的一个或多个 Endpoint, 类似 Kubernetes 中 Service 概念,即一个 Service 提供多个相同服务的 Pod;
- Route:当我们做金丝雀发布部署时,同一个服务会有多个版本,这时需要 Route 规则规定请求如何路由到其中的某个版本上。
xDS 模块的功能是通过 Envoy API V1(基于 HTTP)或 V2(基于 gRPC)实现一个服务端将配置信息暴露给上游主机,等待上游主机的拉取。
Envoy 正常的工作流程为 Host A(下游主机)发送请求至上游主机(Host B、Host C、Host D 等),Envoy 通过 Listener 监听到有下游主机的请求,收到请求后的 Envoy 将所有请求流量劫持至 Envoy 内部,并将请求内容抽象为 Filter Chains 路由至某个上游主机中从而实现路由转发及负载均衡能力。
Envoy 为了实现流量代理能力通常需要一个统一的配置文件来记录信息以便启动时加载,在 Envoy 中启动配置文件有静态配置和动态配置两种方式。静态配置是将配置信息写入文件中,启动时直接加载,动态配置通过 xDS 实现一个 Envoy 的服务端(可以理解为以 API 接口对外实现服务发现能力)。
Network Topology
Envoy 作为 Service Mesh 中的 sidecar 代理,请求可以通过 ingress 或者 egress listener 到达 envoy。
- Ingress Listener 负责从服务网格中其他节点接受请求,并将请求转发到本地应用。本地应用的响应之后通过 Envoy 转发到 downstream。
- Egress Listener 负责从本地应用接受请求,并将请求转发到服务网格中的其他节点。
除了服务网格外,Envoy 还可以用作很多其他的请求,比如作为内部的负载均衡器:
或者作为网络边缘的 ingress/egress 代理:
在实际应用中,Envoy 一般会发挥上述多种功能,一个网络请求路径中可能会通过多个 Envoy:
为了可靠性和可扩充性,Envoy 可能会被配置成多层拓扑的形式:
High Level Architecture
Envoy 中服务请求处理过程可以大致分为两个部分:
- Listener 子系统:处理来自 downstream 的请求。
- Cluster 子系统:负责选择和配置 upstream 连接。
Envoy 采用了基于事件的线程模型:
- 一个主线程负责 server 的生命周期,配置处理,统计等
- 多个 worker 线程负责处理请求。
所有的线程都运行在一个基于 libevent 的事件循环中,任何 downstream 的 TCP 连接都会被分配一个 work 线程来处理
过滤器
Envoy 进程中运行着一系列 Inbound/Outbound 监听器(Listener),Inbound 代理入站流量,Outbound 代理出站流量。Listener 的核心就是过滤器链(FilterChain),链中每个过滤器都能够控制流量的处理流程。过滤器链中的过滤器分为两个类别:
- 网络过滤器(Network Filters): 工作在
L3/L4,是 Envoy 网络连接处理的核心,处理的是原始字节,分为Read、Write和Read/Write三类。 - HTTP 过滤器(HTTP Filters): 工作在
L7,由特殊的网络过滤器HTTP connection manager管理,专门处理HTTP1/HTTP2/gRPC请求。它将原始字节转换成HTTP格式,从而可以对HTTP协议进行精确控制。
除了 HTTP connection manager 之外,还有一种特别的网络过滤器叫 Thrift Proxy。Thrift 是一套包含序列化功能和支持服务通信的 RPC 框架,详情参考维基百科。Thrift Proxy 管理了两个 Filter:Router 和 Rate Limit。
除了过滤器链之外,还有一种过滤器叫监听器过滤器(Listener Filters),它会在过滤器链之前执行,用于操纵连接的元数据。这样做的目的是,无需更改 Envoy 的核心代码就可以方便地集成更多功能。例如,当监听的地址协议是 UDP 时,就可以指定 UDP 监听器过滤器。根据上面的分类,Envoy 过滤器的架构如下图所示:
Request Flow
Listener TCP Accept
Listener filter chains and network filter chain matching
TLS transport socket decryption
Network filter chain processing
HTTP/2 codec encoding
TLS transport socket encryption
Load Balancing
Response path and HTTP lifecycle
Post-request processing
参考资料
-
No backlinks found.