概述
Envoy 是专为大型现代 SOA(面向服务架构)架构设计的 L7 代理和通信总线,它是Istio中的Sidecar官方标配。由C++11编写而成,具有良好的性能。sidecar模式部署,对业务无侵入。
image.png
支持的特性包括:L3/L4层代理、HTTP代理、顶级的HTTP2.0支持、gRPC支持、服务发现、健康检查、高级负载均衡、前端/边缘代理支持、最佳的可观察性和xDS动态配置等。
image.png
Envoy 接收到请求后,会先走 FilterChain,通过各种 L3/L4/L7 Filter 对请求进行微处理,然后再路由到指定的集群,并通过负载均衡获取一个目标地址,最后再转发出去。
其中每一个环节可以静态配置,也可以动态服务发现,也就是所谓的 xDS。这里的 x 是一个代词,代表一系列的Discovery Service。
基本术语
再次介绍一下基本术语。
- Host:能够进行网络通信的实体(在手机或服务器等上的应用程序)。在 Envoy 中主机是指逻辑网络应用程序。只要每台主机都可以独立寻址,一块物理硬件上就运行多个主机。
- Downstream:下游(downstream)主机连接到 Envoy,发送请求并或获得响应。
- Upstream:上游(upstream)主机获取来自 Envoy 的链接请求和响应。
- Cluster: 集群(cluster)是 Envoy 连接到的一组逻辑上相似的上游主机。Envoy 通过服务发现发现集群中的成员。Envoy 可以通过主动运行状况检查来确定集群成员的健康状况。Envoy 如何将请求路由到集群成员由负载均衡策略确定。
- 运行时配置:与 Envoy 一起部署的带外实时配置系统。可以在无需重启 Envoy 或 更改 Envoy 主配置的情况下,通过更改设置来影响操作。
- Listener/监听器:监听器是命名网络地址(例如,端口、unix domain socket等),可以被下游客户端连接。Envoy 暴露一个或者多个监听器给下游主机连接。
- 监听器过滤器 (Listener filter) :Listener 使用 listener filter(监听器过滤器)来操作链接的元数据。它的作用是在不更改 Envoy 的核心功能的情况下添加更多的集成功能。
过滤器链
Listener 的核心就是过滤器链(FilterChain),链中每个过滤器都能够控制流量的处理流程。过滤器链中的过滤器分为两个类别:
-
网络过滤器(Network Filters): 工作在 L3/L4,是 Envoy 网络连接处理的核心,处理的是原始字节,分为 Read、Write 和 Read/Write 三类。
-
HTTP/L7 过滤器(HTTP Filters): 工作在 L7,HTTP过滤器由特殊的网络过滤器 HTTP connection manager 管理,专门处理 HTTP1/HTTP2/gRPC 请求。它将原始字节转换成 HTTP 格式,从而可以对 HTTP 协议进行精确控制。
Envoy 过滤器的架构如下图所示:
image.png
Filter Chain的调用顺序:
以http为例, HttpConnectionManager在完成HTTP数据解析之后,会依次调用Http Filter提供的接口,对HTTP数据做进一步处理(简单的处理如替换header、复杂的处理如限流、错误注入、缓存等等)。Envoy丰富而强大的功能,很多都是依赖Filter来实现。大部分情况下,在对Envoy做扩展增强时,也是通过扩展Filter来做到。以Http Filter为例,实际工作流程如下图所示:
image.pngRouter Router是一个特殊的Filter, 它决定Listener在接收到下游连接和数据之后,应该将数据交给哪一个Cluster处理。它定义了数据分发的规则。
配置说明
管理接口配置
admin:
- access_log_path: /var/logs/admin.log #(required, string) 管理服务器的访问日志的路径。如果不需要访问日志,则指定"/dev/null"。
- profile_path: /var/logs/profile #(optional, string) 管理服务器的cpu分析器的文件路径。如果配置未指定,则默认路径为"/var/log/envoy/envoy.prof"
address: #(required, string) 管理服务器将监听的地址,可以为socket地址也可以为uds。
socket_address: { address: 0.0.0.0, port_value: 8888}
管理接口的使用说明参见 Administration interface — envoy 1.21.0-dev-86ddd4 documentation
静态配置
image.png配置加载流程
如上图所示,服务启动时静态配置的解析过程如下:
1.读取listeners配置,监听socket地址或者uds(unix domain socket)
2.读取filter_chains配置,创建L4级Network Filters,这里是 envoy.http_connection_manager
3.读取L7级Filters配置,这里是http_filters,根据各个filter的配置创建对应filter的回调函数供http_connection_manager回调。根据各个filter实现的不同,会挂载到decoder_filters链或encoder_filters链
4.router filter作为一种特殊的filter还会读取route_config,以获取路由配置
请求解析与处理流程
当有下游请求连接时,filter_chains的处理流程如下:
1.匹配对应的listener
2.listener依次调用自己的filter_chains
3.解析数据头,根据decoder_filters链创建decoder filters 并依次调用
4.在调用router filter(一种特殊的decoder filter)时根据route_config匹配到对应的route信息
5.根据route信息找到对应的cluster
6.根据cluster的负载均衡策略选取end point
7.通过连接池建立与上游主机的连接,并发送请求
请求响应流程:
1.接收到请求响应之后,解析数据头
2.回调router filter中的请求响应回调函数
3.根据encoder_filters配置调用encoder filters
4.向下游主机发送响应
filter 调用示例
有如下filter chain
image.png则请求顺序为:
image.png
响应顺序为:
image.png4.3 动态配置
动态资源,是指由envoy通过xDS协议发现所需要的各项配置的机制,相关的配置信息保存于管理服务器Pilot的主机上,经由xDS API向外暴露;下面是一个动态资源的示例:
dynamic_resources:
cds_config:
ads: {}
resource_api_version: V3
initial_fetch_timeout: 0s
ads_config:
api_type: DELTA_GRPC # api类型 string,REST_LEGACY/REST/GRPC"
transport_api_version: V3 #api版本
grpc_services: # string,只用于GRPC,可以配置多个
- envoy_grpc:
cluster_name: xds_grpc #cluster名称,可以指向static_resources中的一个cluster
5 xDS
xDS 是一个关键概念,它是一类发现服务的统称,其包括如下几类:
- CDS:Cluster Discovery Service 用于动态发现上游cluster信息
- EDS:Endpoint Discovery Service 用于动态发现服务端点
- SDS:Secret Discovery Service 用于动态发现证书
- RDS:Route Discovery Service 用于发现路由配置
- LDS:Listener Discovery Service 用于动态发现Listener
Envoy通过xDS协议与控制面实现配置数据的交换,Envoy配置下发流程如下图所示:
image.png虽然Filter本身并没有专门的xDS服务来发现配置。但Filter所有配置都是嵌入在LDS、RDS以及CDS中的,可以通过xDS影响Filter的配置。
xDS以及各个资源之间的关系如下图所示:
image.pngenvoy配置概述
1、envoy启动时从Bootstrap配置文件中加载初始配置。
2、支持静态和动态配置。
静态配置:
纯手工指定配置。
动态配置:
1)xDS API
-
从配置文件加载配置
-
从管理服务器(Management Server )基于xds协议加载配置
2) runtime
-
某些关键特性(Feature flags )保存为key/value 数据
-
支持多层配置和覆盖机制
3、启用全动态配置机制后,仅极少数场景需要重新启动Envoy进程。
支持热重启。
4、Envoy的架构支持非常灵活的配置方式:简单部署场景可以使用纯静态配置,而更复 杂的部署场景则可以逐步添加需要的动态配置机制。
- 纯静态配置:用户自行提供侦听器、过滤器链、集 群及HTTP路由(http代理场景),上游端点的发现仅可通过DNS服务进行,且配置的重新加载必须通过内置的热重启(hot restart)完成;
- 仅使用EDS:EDS提供的端点发现功能可有效规避DNS的限制(响应中的最大记录数等);
- 使用EDS和CDS:CDS能够让Envoy以优雅的方式添加、更新和删除上游集群 ,于是,初始配置时,Envoy无须事先了解所有上游集群;
- EDS、CDS和RDS:动态发现路由配置;RDS与EDS、CDS一起使用时 ,为用户 提供了构 建复杂路 由 拓扑的能力(流量转移、蓝/绿部署等);
- EDS、CDS、RDS和LDS:动态发现侦听器配置,包括内嵌的过滤 器链;启 用此四种 发现服务 后,除 了较罕见的配置变动、证书轮替或更新Envoy程序之外,几 乎无须再 热重启Envoy;
- EDS、CDS、RDS、LDS和SDS:动态发现侦听器密钥相关的证书、 私钥及TLS会 话票据, 以及对证 书 验证逻辑的配置(受信任的根证书和撤销机制等 );
二、Envoy配置中的重要概念
1、Bootstrap配置中几个重要的基础概念
- node:节点标识,以呈现给管理服务器并且例如用于标识目的 ;
- static_resources:静态配置的资源,用于配置静态的listener、cluster和 secret;
- dynamic_resources:动态配置的资源,用于配置基于xDS API获 取listener、cluster和secret配置的lds_config、cds_config和ads_config;
- admin:Envoy内置的管理接口;
- tracing:分布式跟踪;
- layered_runtime:层级化的 运行时,支持使用RTDS从 管理服务器动态加载;
- hds_config:使用HDS从管理服 务器加载上游主机健康状态检测相关的配置;
- overload_manager: 过载管理器;
- stats_sinks:统计信息接收器;
{
"node": "{...}",
"static_resources": "{...}",
"dynamic_resources": "{...}",
"cluster_manager": "{...}",
"hds_config": "{...}",
"flags_path": "...",
"stats_sinks": [],
"stats_config": "{...}",
"stats_flush_interval": "{...}",
"stats_flush_on_admin": "...",
"watchdog": "{...}",
"watchdogs": "{...}",
"tracing": "{...}",
"layered_runtime": "{...}",
"admin": "{...}",
"overload_manager": "{...}",
"enable_dispatcher_stats": "...",
"header_prefix": "...",
"stats_server_version_override": "{...}",
"use_tcp_for_dns_lookups": "...",
"bootstrap_extensions": [],
"fatal_actions": [],
"default_socket_interface": "..."
}
2、侦听器和集群是最为常用基础配置,无论是以静态或者是 动态方式提供;
三、侦听器和集群配置基础
1、侦听器 listener
侦听器(Listener
)就是 Envoy 的监听地址,可以是端口或 Unix Socket
。Envoy 在单个进程中支持任意数量的监听器。通常建议每台机器只运行一个 Envoy 实例,每个 Envoy 实例的监听器数量没有限制,这样可以简化操作,统计数据也只有一个来源,比较方便统计。目前 Envoy 支持监听 TCP
协议和 UDP
协议。
TCP
每个监听器都可以配置多个过滤器链(Filter Chains),监听器会根据 filter_chain_match
中的匹配条件将流量转交到对应的过滤器链,其中每一个过滤器链都由一个或多个网络过滤器(Network filters
)组成。这些过滤器用于执行不同的代理任务,如速率限制,TLS
客户端认证,HTTP
连接管理,MongoDB
嗅探,原始 TCP 代理等。
除了过滤器链之外,还有一种过滤器叫监听器过滤器(Listener filters),它会在过滤器链之前执行,用于操纵连接的元数据。这样做的目的是,无需更改 Envoy 的核心代码就可以方便地集成更多功能。例如,当监听的地址协议是 UDP
时,就可以指定 UDP 监听器过滤器。
UDP
Envoy 的监听器也支持 UDP
协议,需要在监听器过滤器中指定一种 UDP 监听器过滤器(UDP listener filters)。目前有两种 UDP 监听器过滤器:UDP 代理(UDP proxy) 和 DNS 过滤器(DNSfilter)。UDP 监听器过滤器会被每个 worker
线程实例化,且全局生效。实际上,UDP 监听器(UDP Listener)配置了内核参数 SO_REUSEPORT
,这样内核就会将 UDP 四元组相同的数据散列到同一个 worker
线程上。因此,UDP 监听器过滤器是允许面向会话(session)的。
每个侦听器可以包含多个L3/L4的过滤器,并对其进行独立配置。
1)侦听器收到的连接请求将由其过滤器链中的各过滤器进行处理; 2)Envoy侦听器构架支持大多数的不同proxy的任务。
如:
rate limiting
TLS client authentication
HTTP connection management
raw TCP proxy
......
侦听器(Listener
)功能:
- 接收客户端请求的入口端点,通常由监听的套接字及调用的过滤器链所定义
2)代理类的过滤器负责路由请求,例如tcp_proxy和http_connection_manager等
监听器的配置结构如下:
{
"name": "...",
"address": "{...}",
"filter_chains": [],
"per_connection_buffer_limit_bytes": "{...}",
"metadata": "{...}",
"drain_type": "...",
"listener_filters": [],
"listener_filters_timeout": "{...}",
"continue_on_listener_filters_timeout": "...",
"transparent": "{...}",
"freebind": "{...}",
"socket_options": [],
"tcp_fast_open_queue_length": "{...}",
"traffic_direction": "...",
"udp_listener_config": "{...}",
"api_listener": "{...}",
"connection_balance_config": "{...}",
"reuse_port": "...",
"access_log": []
}
- name : 监听器名称。默认情况下,监听器名称的最大长度限制为 60 个字符。可以通过 --max-obj-name-len 命令行参数设置为所需的最大长度限制。
-address : 监听器的监听地址,支持网络 Socket 和 Unix Domain Socket(UDS) 两种类型。
filter_chains : 过滤器链的配置。
-per_connection_buffer_limit_bytes : 监听器每个新连接读取和写入缓冲区大小的软限制。默认值是 1MB。
-listener_filters : 监听器过滤器在过滤器链之前执行,用于操纵连接的元数据。这样做的目的是,无需更改 Envoy 的核心代码就可以方便地集成更多功能。例如,当监听的地址协议是 UDP 时,就可以指定 UDP 监听器过滤器。
-listener_filters_timeout : 等待所有监听器过滤器完成操作的超时时间。一旦超时就会关闭 Socket,不会创建连接,除非将参数 continue_on_listener_filters_timeout 设为 true。默认超时时间是 15s,如果设为 0 则表示禁用超时功能。
-continue_on_listener_filters_timeout : 布尔值。用来决定监听器过滤器处理超时后是否创建连接,默认为 false。
-freebind : 布尔值。用来决定是否设置 Socket 的 IP_FREEBIND 选项。如果设置为 true,则允许监听器绑定到本地并不存在的 IP 地址上。默认不设置。
-socket_options : 额外的 Socket 选项。
-tcp_fast_open_queue_length : 控制 TCP 快速打开(TCP Fast Open,简称 TFO)。TFO 是对TCP 连接的一种简化握手手续的拓展,用于提高两端点间连接的打开速度。它通过握手开始时的 SYN 包中的 TFO cookie(一个 TCP 选项)来验证一个之前连接过的客户端。如果验证成功,它可以在三次握手最终的 ACK 包收到之前就开始发送数据,这样便跳过了一个绕路的行为,更在传输开始时就降低了延迟。该字段用来限制 TFO cookie 队列的长度,如果设为 0,则表示关闭 TFO。
-traffic_direction : 定义流量的预期流向。有三个选项:UNSPECIFIED、INBOUND 和 OUTBOUND,分别代表未定义、入站流量和出站流量,默认是 UNSPECIFIED。
-udp_listener_config : 如果 address 字段的类型是网络 Socket,且协议是 UDP,则使用该字段来指定 UDP 监听器。
-connection_balance_config : 监听器连接的负载均衡配置,目前只支持 TCP。
-reuse_port : 布尔值。用来决定是否设置 Socket 的 SO_REUSEPORT 选项。如果设置为 true,则会为每一个 worker 线程创建一个 Socket,在有大量连接的情况下,入站连接会均匀分布到各个 worker 线程中。如果设置为 false,所有的 worker 线程共享同一个 Socket。
-access_log : 日志相关的配置。
2、集群 cluster service
-
一组上游主机的逻辑组合
-
每个主机映射为集群中的一个端点
-下游的请求被调度至上游主机
image3、Upstream clusters
- Envoy可配置任意数量的上游集群,并使用Cluster Manager进行管理。
(1)由集群管理器负责管理的各集群可以由用户静态配置,也可借助于CDS API动态获取;
(2)集群中的每个成员由endpoint进行标识,它可由用户静态配置,也可通过EDS或DNS服务 动态发现;
- Static :静态配置
- Strict DNS:严格DNS,Envoy将持续和异步地解析指定的DNS目标,并将DNS结果中的返回的每 个IP地址视为上游集群中可用成员;
- Logical DNS:逻辑DNS,集群仅使用在需要启动新连接时返回的第一个IP地址,而非严格获取 DNS查询的结果并假设它们构成整个上游集群;适用于必须通过DNS访问的大规模Web服务集群;
- Original destination:当传入连接通过iptables的REDIRECT或TPROXY target或使用代理协议重定向 到Envoy时,可以使用原始目标集群;
- Endpoint discovery service (EDS) :EDS是一种基于GRPC或REST-JSON API的xDS 管理服务器获取集 群成员的服务发现方式;
- Custom cluster :Envoy还支持在集群配置上的cluster_type字段中指定使用自定义集群发现机制;
-
每个Cluster主要由集群名称,以及集群 中的端点(通常是提供服务的IP地址和 端口)所组成。
-
Envoy Cluster支持纯静态定义方式来指 定端点,也允许以动态方式发现各端点, 甚至还支持自定义的发现机制。
-
支持用户定义多种高级功能,例如,负 载均衡策略、主动健康状态检查、被动 健康状态检查和断路器等。
{
"transport_socket_matches": [],
"name": "...",
"alt_stat_name": "...",
"type": "...",
"cluster_type": "{...}",
"eds_cluster_config": "{...}",
"connect_timeout": "{...}",
"per_connection_buffer_limit_bytes": "{...}",
"lb_policy": "...",
"load_assignment": "{...}",
"health_checks": [],
"max_requests_per_connection": "{...}",
"circuit_breakers": "{...}",
"upstream_http_protocol_options": "{...}",
"common_http_protocol_options": "{...}",
"http_protocol_options": "{...}",
"http2_protocol_options": "{...}",
"typed_extension_protocol_options": "{...}",
"dns_refresh_rate": "{...}",
"dns_failure_refresh_rate": "{...}",
"respect_dns_ttl": "...",
"use_tcp_for_dns_lookups": "...",
"outlier_detection": "{...}",
"cleanup_interval": "{...}",
"upstream_bind_config": "{...}",
"lb_subset_config": "{...}",
"ring_hash_lb_config": "{...}",
"maglev_lb_config": "{...}",
"original_dst_lb_config": "{...}",
"least_request_lb_config": "{...}",
"common_lb_config": "{...}",
"transport_socket": "{...}",
"metadata": "{...}",
"protocol_selection": "...",
"upstream_connection_options": "{...}",
"close_connections_on_host_health_failure": "...",
"ignore_health_on_host_removal": "...",
"filters": [],
"track_timeout_budgets": "...",
"upstream_config": "{...}",
"track_cluster_stats": "{...}",
"preconnect_policy": "{...}",
"connection_pool_per_downstream_connection": "..."
}
四、Network (L3/L4) filters
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 监听器过滤器。
1、网络级(L3/L4)过滤器构成了Envoy连接处理的核心
1)过滤器API允许将不同的过滤器集混合、匹配并附加到给定的侦听器。 2)有三种不同类型的网络过滤器:
Read:当Envoy从下游连接接收数据时,读取过滤器被调用。
Write:当Envoy正要将数据发送到下游连接时,会调用Write filter。
Read/Write:当Envoy从下游连接接收数据和将要向下游连接发送数据时,会调用读/写过滤器。 3)网络级过滤器的API相对简单,因为最终过滤器只操作原始字节和少量连接事件。 4)链中的过滤器可能会停止,随后继续迭代进一步筛选。
2、网络过滤器访问和操作L4连接上的原始数据,即TCP数据包
例如,TCP代理过滤器将客户端连接数据路由到上游主机,并生成连接统计信息等
3、Enovy内置了许多L3/L4过滤器
代理类:TCP Proxy、HTTP connection manager、Thrift Proxy、Mongo proxy、Dubbo Proxy、 ZooKeeper proxy、MySQL proxy和Redis proxy等,
◼其它:Client TLS authentication、Rate limit、Role Based Access Control (RBAC) Network Filter 和Upstream Cluster from SNI 等;
4、HTTP connection manager
(1)HTTP connection manager自身是L3/L4 过路器,它能够将原始字节转换为HTTP级别消息 和事件(例如,headers和body等)
(2)它还处理所有HTTP连接和请求共有的功能,例如访问日志记录、请求ID生成和跟踪、 请求/响应头操作、路由表管理和统计信息等;
(3)与L3/L4过滤器堆栈相似,Envoy还支持在HTTP连接管理器中使用HTTP级过滤器堆栈;
HTTP过滤器在L7运行,它们访问和操作HTTP请求和响应;例如,gRPC-JSON Transcoder Filter为gRPC后端公开REST API,并将请求和响应转换为相应的格式;
常用的HTTP过路器有Router、Rate limit 、Health check 、Gzip和Fault Injection等。
五、Envoy线程模型
Envoy使用单进程/多线程的架构模型,一个主线程 (Main thread)负责实现各类管理任务,而一些工作线 程(Worker threads)则负责执行监听、过滤和转发等代 理服务器的核心功能。
主线程:负责Envoy程序的启动和关闭、xDS API调用处 理(包括DNS、健康状态检测和集群管理等)、运行时配 置、统计数据刷新、管理接口维护和其它线程管理(信号 和热重启等)等,相关的所有事件均以异步非阻塞模式完成.
工作线程:默认情况下,Envoy根据当前主机CPU核心数 来创建等同数量的工作线程,不过,管理员也可以通过程 序选项--concurrency具体指定;每个工作线程运行一个非 阻塞型事件循环,负责为每个侦听器监听指定的套接字、接收新请求、为每个连接初始一个过滤器栈并处理此连接 整个生命周期中的所有事件。
文件刷写线程:Envoy写入的每个文件都有一个专用、独 立的阻塞型刷写线程,当工作线程需要写入文件时,数据 实际上被移入内存缓冲区,最终通过文件刷写线程同步至文件中。
image六、Envoy连接处理
Envoy通过侦听器监听套接字并接收客户端请求,而Envoy的所有工作线程会同时共同监听用 户配置的所有套接字,对于某次连接请求,由内核负责将其派发至某个具体的工作线程处理; 随后,相关的工作线程基于特定的处理逻辑分别由相关组件依次完成连接管理。
image
网友评论