一、Envoy基础概念学习
因语雀和CSDN MarkDown格式有区别,导入到CSDN时可能会有格式显示问题,请查看原文链接:
https://www.yuque.com/dycloud/pss8ys/vgut6pqokb39oh1k
一、Envoy 基础
1.1 什么是 Envoy
Envoy 是现代云原生架构中的高性能开源边缘和服务代理,是用 C++开发的高性能代理, 由 Lyft 公司开发并捐赠给 CNCF(云原生计算基金会)。它专为分布式系统设计,核心功能是处理服务间的网络通信,是服务网格(如 Istio)的数据平面核心组件。
Envoy 是一个独立的进程,旨在与每个应用程序服务器一起运行。所有 **<font style="color:#DF2A3F;background-color:rgb(252, 252, 252);">Envoy</font>**
都形成一个透明的通信网格,其中每个应用程序都向 localhost 发送和接收消息,并且不需要知道网络拓扑。与传统的库式服务到服务通信方法相比,进程外体系结构有两个实质性的好处:
<font style="color:#DF2A3F;background-color:rgb(252, 252, 252);">Envoy</font>
适用于任何应用程序语言。单个 Envoy 部署可以在 Java、C++、Go、PHP、Python 等之间形成网格。面向服务的架构使用多种应用程序框架和语言变得越来越普遍。Envoy 透明地弥合了这一差距。- 任何使用过大型面向服务架构的人都知道,部署库升级可能会非常痛苦。Envoy 可以在整个基础设施中透明地快速部署和升级。
1.2 Envoy 核心特性
1.2.1 L3/L4 层过滤器架构
Envoy 的核心是一个 L3/L4 网络代理。可插拔 过滤器链机制允许编写过滤器来执行不同的 TCP/UDP 代理任务并插入到主服务器中。Envoy 社区已经提供了很多过滤器以支持各种任务,例如原始 TCP 代理、UDP 代理、HTTP 代理、TLS 客户端证书身份验证、Redis、 MongoDB、Postgres 等。
1.2.2 HTTP L7 层过滤器
HTTP 是现代应用程序架构的关键组件,Envoy 支持额外的 HTTP L7 过滤层。HTTP 过滤器可以插入 HTTP 连接管理子系统,以执行不同的任务,例如缓冲、速率限制、路由/转发、嗅探 Amazon 的 DynamoDB 等。
1.2.3 HTTP L7 路由
在 HTTP 模式下运行时,Envoy 支持 能够根据路径、权限、内容类型、运行时值等路由和重定向请求的路由子系统。此功能在使用 Envoy 作为前端/边缘代理时最有用,但在构建服务到服务网格时也会利用。
1.2.4 gRPC 支持
gRPC 是 Google 的 RPC 框架,它使用 HTTP/2 或更高版本作为底层多路复用传输。Envoy 支持用作 gRPC 请求和响应的路由和负载平衡基础所需的所有 HTTP/2 功能。这两个系统非常互补。
1.2.5 服务发现和动态配置
Envoy 可选择使用一组分层的 用于集中管理的动态配置 API。 这些层为 Envoy 提供了有关以下内容的动态更新:后端集群中的主机、 后端集群本身、HTTP 路由、侦听套接字和加密材料。 为了简化部署,后端主机发现可以是 通过 DNS 解析完成 (甚至 完全跳过),其他层被静态配置文件替换。
1.2.6 健康检查
内置健康状态检测子系统,支持对上游服务集群进行主动式健康状态监测 Enovy基于服务发现和健康状态监测信息判定上游集群中健康可用的端点。
1.2.7 高级负载均衡
分布式系统中不同组件之间的负载均衡是一个复杂的问题。由于 Envoy 是一个独立的代理而不是库,因此它能够在一个地方实现高级负载平衡技术,并让任何应用程序都可以访问它们。目前 Envoy 包括对自动重试、断路、 通过外部速率限制服务进行全局速率限制, 请求镜像, 以及 异常值检测。
1.2.8 前端/边缘代理支持
在边缘使用相同的软件(可观察性、管理、相同的服务发现和负载平衡算法等)具有巨大的好处。Envoy 具有一组功能,非常适合作为大多数现代 Web 应用程序用例的边缘代理。这包括 TLS 终止、HTTP/1.1 HTTP/2 和 HTTP/3 支持,以及 HTTP L7 路由。
1.2.9 一流的可观测性
内置支持对各子系统生成统计信息,默认以statsD为statistics sink,以及通过admin接口对外暴露
支持链路跟踪
1.3 Envoy 核心组件
1.3.1 监听器(Listener)
监听器是 Envoy 中的网络入口点,绑定特定地址和端口用于接收流量。
- 支持 TCP/UDP协议监听
- TLS 终止与证书管理
- 协议自动检测(如 HTTP/1.1 到 HTTP/2 的自动升级)
- 关联过滤器链处理流量
https://www.envoyproxy.io/docs/envoy/v1.35.0/api-v3/config/listener/v3/listener.proto#envoy-v3-api-msg-config-listener-v3-listener
{"name": "...", // 监听器的名称,便于标识和管理"address": {...}, // 监听器监听的 IP 地址和端口,决定了入站请求的接收终端"additional_addresses": [], // 额外绑定的地址,可用于多网卡或多地址绑定场景"stat_prefix": "...", // 用于生成监听器相关监控统计指标时的前缀"filter_chains": [], // 过滤器链数组,定义连接在流程中的一系列过滤器处理逻辑"filter_chain_matcher": {...}, // 可用于动态选择匹配哪个过滤器链的高级匹配器"use_original_dst": {...}, // 是否使用原始目的地址,常用于透明代理或重定向场景"default_filter_chain": {...}, // 默认过滤器链,所有未被其他chain匹配到的连接将使用此链"per_connection_buffer_limit_bytes": {...}, // 每个连接在Envoy内部可用的缓冲区字节上限"metadata": {...}, // 附加元数据,比如标签、版本号、环境信息等,为上游扩展或插件增强用"drain_type": "...", // 监听器的排空类型: graceful(优雅关闭)、immediate(立即关闭)等"listener_filters": [], // 监听器级别的过滤器(比如用于连接建立时的SNI提取、Proxy Protocol解析等)"listener_filters_timeout": {...}, // 监听器过滤器的超时时间,超时未完成则可终止或跳过"continue_on_listener_filters_timeout": ..., // 监听器过滤器超时后是否继续后续流程"transparent": {...}, // 是否启用透明代理(不更改被代理流量的源地址)"freebind": {...}, // 是否允许在本地IP还未分配到本机时提前绑定端口(少数网络环境需要)"socket_options": [], // 绑定socket时需要配置的底层选项(如TCP fast open、keepalive等)"tcp_fast_open_queue_length": {...}, // TCP Fast Open队列长度,提升建立连接效率"traffic_direction": "...", // 标识监听器流量方向,比如INBOUND(入站)或OUTBOUND(出站)"udp_listener_config": {...}, // 针对UDP协议监听的专用配置,主要用于Datagram传输"api_listener": {...}, // 支持“API驱动型Listener”,如gRPC代理用于与xDS API交互"connection_balance_config": {...}, // 多线程时对连接分配策略配置,提高连接处理均衡"reuse_port": ..., // [已废弃] 是否多进程/多线程下允许端口重用(通常用enable_reuse_port)"enable_reuse_port": {...}, // 是否启用端口重用,高并发高可用场景下常用"access_log": [], // 此监听器级别的访问日志配置"tcp_backlog_size": {...}, // TCP listen socket的backlog参数(队列长度)"max_connections_to_accept_per_socket_event": {...}, // 每一次socket事件上最大允许的accept数量,防止单次突发流量压垮服务"bind_to_port": {...}, // 是否实际绑定物理端口(某些情况下仅内部转发可为false)"internal_listener": {...}, // 配置内部监听器(仅用于Envoy自身组件间通信,非对外开放接口)"enable_mptcp": ..., // 是否启用多路径TCP(MPTCP)功能,高可用和高通量场景可用"ignore_global_conn_limit": ..., // 是否忽略全局连接限制策略,仅对部分流量放宽连接数限制"bypass_overload_manager": ... // 是否绕过过载管理器(Overload Manager),某些特殊流量可配置为永不关闭
}
示例:
listeners:
- name: main_listeneraddress: socket_address: address: 0.0.0.0port_value: 8080filter_chains: [...] # 过滤器链配置
1.3.2 过滤器(Filter)
监听器过滤器主要用途:无需更改就可以轻松的添加更多 Envoy 支持的核心功能,也可以使多个功能之间交互更加丰富。
过滤器链:
每个 Listener 监听器可以有多个过滤器和一个默认的过滤器(可选),请求到达后,会根据你写的匹配规则来选择符合条件的过滤器 FilterChain,如果没有找到匹配的 FilterChain,就会使用默认的过滤器来处理请求(如果配置了),否则将会关闭链接。
Envoy 内置了很多 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等;
{"filter_chain_match": {...}, // 匹配条件,用于决定外部连接是否由此Filter Chain处理,比如根据SNI、目标端口、来源IP等字段识别不同客户端的请求"filters": [], // 在此Filter Chain中要应用的一系列过滤器(如HTTP连接管理器、TCP代理等),依次处理流量"use_proxy_proto": {...}, // 是否启用PROXY协议(Proxy Protocol),用于识别经过L4负载均衡器时原始客户端的IP和端口(如Nginx、HAProxy场景)"transport_socket": {...}, // 定义底层传输套接字配置,如TLS/SSL安全通信、加密通信等(如类型为“tls”时配置证书等信息)"transport_socket_connect_timeout": {...}, // 连接建立时传输层套接字的超时时间,防止连接握手过程阻塞太久"name": ... // 本Filter Chain的名称,便于管理、监控和排障
}
listener_filters:- name: "envoy.filters.listener.http_inspector"typed_config:"@type": type.googleapis.com/envoy.extensions.filters.listener.http_inspector.v3.HttpInspector
过滤器的 typed_config 有很多,可以查看官网选择自己需要的
https://www.envoyproxy.io/docs/envoy/v1.35.0/api-v3/config/listener/v3/listener_components.proto#envoy-v3-api-msg-config-listener-v3-filter
1.3.3 路由(Router)
主要作用于 HTTP 过滤器中,根据请求路径、头部、参数等对流量进行转发和分流,决定请求要去哪一个 Cluster(集群),可以实现路由重写、流量镜像、AB 测试、蓝绿发布、金丝雀发布等场景的实现。
1.3.4 集群(Cluster)
https://www.envoyproxy.io/docs/envoy/v1.35.0/configuration/upstream/cluster_manager/cluster_stats#general
集群是一组上游主机的逻辑组合,每个主机映射成集群中的一个断电,下游的请求被调度到上游主机。他可以实现服务发现(静态/DNS/EDS)、连接池管理、健康状态维护、负载均衡策略等。
每个 Cluster 主要由集群名称,以及集群中的端点(通常是提供服务的 IP 和端口组成),EnvoyCluster 支持纯静态定义方式来指定端点,也支持以动态方式发现各端点,甚至还支持自定义的发现机制,还支持用户定义多种高级功能,例如:负载均衡策略、主动健康状态检查、被动健康状态检查和断路器等。
类型 | 发现方式 | 适用场景 |
---|---|---|
STATIC | 静态配置 | 固定后端服务 |
STRICT_DNS | DNS轮询 | 传统架构迁移 |
EDS | 动态端点 | 服务网格 |
{"transport_socket_matches": [], // 根据不同的目标主机或端口选择不同的 transport socket 配置(比如针对不同后端启用不同TLS证书)"name": "...", // 集群名称,必须唯一,用于识别和引用该集群"alt_stat_name": "...", // 指定该集群监控指标的替代名称,方便自定义统计项"type": "...", // 集群类型,如STATIC、STRICT_DNS、LOGICAL_DNS、EDS等,决定服务发现、节点变更的方法"cluster_type": {...}, // 自定义扩展的集群类型配置(一般用于特殊插件场景)"eds_cluster_config": {...}, // Endpoints Discovery Service 配置,启用动态服务发现时所需的参数"connect_timeout": {...}, // 建立与上游服务连接的超时时长"per_connection_buffer_limit_bytes": {...}, // 单个连接缓冲区的最大字节数,超过这个上限会触发流量管控"lb_policy": "...", // 负载均衡策略,如 ROUND_ROBIN、LEAST_REQUEST、RING_HASH等"load_assignment": {...}, // 静态或动态分配集群中的后端节点列表及其属性"health_checks": [], // 健康检查配置数组,定期检测集群中各个节点的可用性"max_requests_per_connection": {...}, // 单条连接最大允许请求数(如HTTP/1 keepalive或HTTP/2复用)"circuit_breakers": {...}, // 熔断器配置,用于防止后端过载或故障自动限流"upstream_http_protocol_options": {...}, // 上游HTTP协议通用选项"common_http_protocol_options": {...}, // HTTP协议所有版本的通用配置项"http_protocol_options": {...}, // HTTP/1.1 协议的相关配置"http2_protocol_options": {...}, // HTTP/2 协议的相关配置"typed_extension_protocol_options": {...}, // 用于扩展自定义协议的配置,基于 typed extension 方式"dns_refresh_rate": {...}, // DNS 动态地址集群的刷新间隔"dns_jitter": {...}, // DNS刷新间隔的随机抖动,防止多个实例同时刷新DNS"dns_failure_refresh_rate": {...}, // DNS解析失败时的重试频率"respect_dns_ttl": ..., // 是否根据DNS返回的TTL值动态调整刷新周期"dns_lookup_family": "...", // DNS查询族,支持AUTO、V4_ONLY、V6_ONLY等"dns_resolvers": [], // 自定义DNS服务器地址清单"use_tcp_for_dns_lookups": ..., // 是否用TCP协议进行DNS解析(默认UDP)"dns_resolution_config": {...}, // DNS解析的详细配置(如EDNS、缓存设置等)"typed_dns_resolver_config": {...}, // 针对typed扩展的DNS resolver配置"wait_for_warm_on_init": {...}, // 初始化阶段是否等待健康检查和服务发现准备就绪"outlier_detection": {...}, // 异常节点检测配置,自动踢除异常后端,提高集群稳定性"cleanup_interval": {...}, // 异常节点检测的周期性清理间隔"upstream_bind_config": {...}, // 连接上游节点时本地网卡IP的绑定配置"lb_subset_config": {...}, // 负载均衡子集配置,用于标签/元数据分流"ring_hash_lb_config": {...}, // 一致性哈希负载均衡详细参数"maglev_lb_config": {...}, // Maglev负载均衡具体参数"original_dst_lb_config": {...}, // Original Destination负载均衡详细参数"least_request_lb_config": {...}, // Least Request负载均衡详细参数"round_robin_lb_config": {...}, // 轮询负载均衡详细参数"common_lb_config": {...}, // 负载均衡的通用配置参数"transport_socket": {...}, // 与上游连接时使用的底层传输配置(如TLS/SSL安全传输等)"metadata": {...}, // 集群元数据,可为过滤器、路由等机制提供服务拓展信息"protocol_selection": "...", // 协议选择策略(如:配置使用下游协议或明确指定协议版本等)"upstream_connection_options": {...}, // 与上游建立连接的Socket相关选项"close_connections_on_host_health_failure": ..., // 后端主机健康检查失败时是否强制关闭当前连接"ignore_health_on_host_removal": ..., // 移除主机时是否忽略其健康状态,决定统计和熔断时机"filters": [], // 集群级别的流量过滤器列表(实验性,较少使用)"load_balancing_policy": {...}, // 支持动态扩展的负载均衡策略,可写复杂dsl(未来特性,暂较少用)"lrs_report_endpoint_metrics": [], // 用于LRS(Load Reporting Service)的端点自定义指标上报设置"track_timeout_budgets": ..., // 是否开启超时预算跟踪,用于精细化流量监控"upstream_config": {...}, // 上游连接的全局自定义扩展配置"track_cluster_stats": {...}, // 是否启用细粒度的集群指标监控选项"preconnect_policy": {...}, // 预连接策略,有利于提升高并发和低延迟"connection_pool_per_downstream_connection": ... // 每个下游连接分配独立连接池,提高上游复用粒度
}
1.3.5 Endpoint
endpoint 就代表一个上游服务的一个实例(真正提供服务的)。
1.4 完整架构设计
Envoy 采用单进程多线程架构。
一个独立的 <font style="color:#DF2A3F;">primary</font>
线程负责控制各种零散的协调任务,而一些 <font style="color:#DF2A3F;">worker</font>
线程则负责执行监听、过滤和转发任务。
一旦侦听器接受连接,该连接就会将其生命周期绑定到一个单独的 <font style="color:#DF2A3F;">worker</font>
线程。这使得 Envoy 的大部分工作基本上是单线程来处理的,只有少量更复杂的代码处理工作线程之间的协调。
通常情况下 Envoy 实现了 100% 非阻塞。对于大多数工作负载,我们建议将 <font style="color:#DF2A3F;">worker</font>
线程的数量配置为机器上的硬件线程数量。
上面已经学习了 Envoy 的核心组件,比较抽象,下面我画了一个完整的 Envoy 架构图:
Listener filters 类型:https://www.envoyproxy.io/docs/envoy/v1.35.0/configuration/listeners/listener_filters/listener_filters
Envoy 进程中运行着一系列 Inbound/Outbound 监听器(Listener),Inbound 代理入站流量,Outbound 代理出站流量。Listener 的核心就是过滤器链(FilterChain),链中每个过滤器都能够控制流量的处理流程。
Envoy 接收到请求后,会先走 <font style="color:#DF2A3F;">FilterChain</font>
,通过各种 L3/L4/L7 Filter 对请求进行处理,然后再路由到指定的集群,并通过负载均衡获取一个目标地址,最后再转发出去。
其中每一个环节可以静态配置,也可以动态服务发现,也就是所谓的 <font style="color:#DF2A3F;">xDS</font>
,这里的 <font style="color:#DF2A3F;">x</font>
是一个代词,是 <font style="color:#DF2A3F;">lds</font>
、<font style="color:#DF2A3F;">rds</font>
、<font style="color:#DF2A3F;">cds</font>
、<font style="color:#DF2A3F;">eds</font>
、<font style="color:#DF2A3F;">sds</font>
的总称,即服务发现,后 2 个字母 <font style="color:#DF2A3F;">ds</font>
就是 <font style="color:#DF2A3F;">discovery service</font>
。
1.5 Envoy API 常用术语
- 主机(Host):一个具有网络通信能力的端点,例如服务器、移动智能设备等
- 集群(Cluster):集群是Envoy连接到的一组逻辑上相似的端点;在v2中,RDS通过路由指向集群,CDS提供集群配置,而Envoy通过EDS发现集群成员,即端点;
- 下游(Downstream):下游主机连接到Envoy,发送请求并接收响应,它们是Envoy的客户端;
- 上游(Upstream):上游主机接收来自Envoy的连接和请求并返回响应,它们是Envoy代理的后端服务器;
- 端点(Endpoint):端点即上游主机,是一个或多个集群的成员,可通过EDS发现;
- 侦听器(Listener):侦听器是能够由下游客户端连接的命名网络位置,例如端口或unix域套接字等;
- 位置(Locality):上游端点运行的区域拓扑,包括地域、区域和子区域等;
- 管理服务器(Management Server):实现v2/v3 API的服务器,它支持复制和分片,并且能够在不同的物理机器上实现针对不同xDS API的API服务;
- 地域(Region):区域所属地理位置;
- 区域(Zone):AWS中的可用区(AZ)或GCP中的区域等;
- 子区域:Envoy实例或端点运行的区域内的位置,用于支持区域内的多个负载均衡目标;
- xDS:CDS 、EDS、HDS 、LDS、RLS(Rate Limit)、 RDS 、 SDS、VHDS和RTDS等API的统称;
- Mesh和Envoy Mesh
1.6 Envoy 部署类型
Envoy通常用于以容器编排系统为底层环境的服务网格中,并以sidecar的形式与主程序容器运行为单个Pod;非编排系统环境中测试时,可以将主程序与Envoy运行于同一容器,或手动组织主程序容器与Envoy容器共享同一网络 名称空间;
具体使用时的常见部署类型如下图所示
**<font style="color:#DF2A3F;">Ingress Listener</font>**
:仅负责代理本地服务的入向流量,并提供buffering和circuit breaking等功能**<font style="color:#DF2A3F;">Egress Listener</font>**
:负责代理本地客户端外发的请求流量,为针对请求的目标服务进行<font style="color:rgb(0,0,0);">service discovery</font>
、<font style="color:rgb(0,0,0);">load balancing</font>
和<font style="color:rgb(0,0,0);">rate limiting</font>
等功能,是服务网格功能实现的关键位置
入向流量代理图:
出向流量代理图: