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 过滤器的架构如下图所示: