Envoy 详解
Envoy 是专为大型现代 SOA(面向服务架构)架构设计的 L7 代理和通信总线,它既可以作为 Service Mesh 中的数据面使用,也可以作为入口网关层使用,可以通过 xDS API 控制 Envoy 的监听、路由、负载均衡等行为。
Envoy 核心功能
- 高性能设计:采用
C++编写,拥有良好的四层、七层代理性能 Filter架构:可以在四、七层编写Filter以扩展Envoy的功能,eg: 监听过滤器、四层网络过滤器,以及七层过滤器。不过Envoy支持最完善的还是HTTP过滤器,支持了限流、路由转发、故障注入等多种服务治理功能,- 良好的
HTTP/2支持:随着gRPC框架的流行以及边缘层网络性能的要求提升,HTTP/2越来越被重视。Envoy原生支持HTTP/2,可以在HTTP和HTTP/2之间做转换。比如在Sidecar模式中,无论应用协议是HTTP还是HTTP/2,Envoy之间默认使用HTTP/2通信,这样极大提升了服务性能和稳定性,避免了HTTP频繁建立连接带来的消耗和不稳定性。 - 多种协议支持:
Thrift、gRPC、MongoDB、Redis、MySQL等多种网络协议都被支持,甚至可以使用Envoy做Redis的Mesh方案,用来代替流行的Redis中间件。 - 可观测性:支持强大的统计系统。日志、
Metrics、链路追踪都有良好的支持。 - 边缘网关:
Envoy本身就是一个高性能的网络代理组件,完全可以作为入口网关层使用,在Kubernetes中,也可以作为Egress和Ingress使用。 - 服务发现:和其他常见的网络代理软件不同,
Envoy默认支持服务发现组件。Envoy使用了一套xDS的动态API,获取服务的后端节点并实时更新,结合Envoy强大的负载均衡器,可以做到最终一致性。 Wasm扩展:Wasm全称为WebAssembly,最早用在浏览器端用来解决JavaScript性能问题和大型项目团队协作问题。近些年,它开始在一些后端技术上使用,用来代替Lua,作为核心系统的扩展方式。因为Wasm可以使用多种语言进行开发,所以方便对核心系统进行扩展,不用担心语言问题。当然相对于原生的C++扩展方式,它大概有 3 成的性能损耗。
Envoy 架构设计

Iptable:通过Iptable劫持,将入口和出口流量都转发到Envoy上,达到劫持流量的目的。Listener:Envoy通过建立多个监听器提供不同的服务。比如通过监听的两个端口分别负责Sidecar模式的出流量和入流量,Sidecar多使用这种设计,这样可以简化编程逻辑,也可以增强Filter的通用性。如果提供不同协议,Envoy也会建立不同的端口来提供服务。Worker:每个Listener维护一个对应的Worker Pool,Envoy为每个逻辑处理器创建一个Worker线程,当我们在一个新的端口启动一个新的server时,Envoy也会根据-concurrency创建对应的Worker线程,要注意启动太多的worker线程并不一定是好事,特别是在Sidecar模式,我们并不会分配过多的逻辑核心给到Sidecar,创建过多的Worker线程可能导致每个Worker线程维护的连接变多,Upstream压力过大。Filters:可以理解为中间件,通过Filter,可以做到四层和七层的流量过滤,支持服务治理需要的限流、熔断等功能。Cluster Manager:流量经过Router,识别出需要转发的Cluster,通过Cluster Manager进行服务发现和负载均衡等功能。Upstream:Upstream维护了EndPoint的连接池,通过负载具衡器,将流量转发到合适的EndPoint上面。
过程示例
Productpage 服务通过 HTTP 协议,调用 review 服务的过程。

通过
Iptables对流量进行劫持,将Productpage访问Reviews的流量转发到Envoy的出流量15001端口上。Envoy先根据virtual_hosts进行匹配,再通过路由匹配,发现路由对应的Cluster,通过服务发现找到Cluster对应的EndPoint,将流量转发到10.40.0.15:9080的Pod上。Reviews的Pod通过Iptables对流量进行劫持,将流量劫持到Envoy的入流量端口15006上。Envoy将本地流量转发到对应的本地地址127.0.0.1:9080,这里不需要对流量进行识别,因为流量被转发到入流量端口15006上,这个端口的配置用于本地流量的转发。到这里整个
Sidecar的流量出入过程就结束了。出入流量都经由Envoy,最终被正确的转发到了Reviews的Pod上面。
Envoy 配置
Envoy 的配置分为静态配置和动态配置
- 静态配置 : 手动填写的配置
- 动态配置 :
xDS API获取的配置
静态配置
eg:
定义 Listener 监听器,监听端口为 10000。virtual_hosts 匹配所有域名,Routes 的匹配规则为所有 Path,也就是所有访问 10000 端口的请求都会被转发到 service_google 服务。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 10000 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"] // 匹配所有域名
routes:
- match: { prefix: "/" }// 匹配所有 path
route: { host_rewrite: www.google.com, cluster: service_google } // 将流量转发到 service_google 服务
http_filters:
- name: envoy.router
service_google
1 | clusters: |
动态配置
通过查询一个或多个管理服务器 获取数据 以发现动态资源变更,比如 Router、Cluster、EndPoint 等,我们把这些发现服务及其对应的 API 称为 xDS 。xDS 最大的价值就是定义了一套可扩展的通用微服务控制 API,这些 API 不仅可以做到服务发现,也可以做到路由发现、集群发现,可以说所有配置都能通过发现的方式解决
xDS 协议: Service Mesh 控制面和数据面的通信桥梁
通过 xDS 协议可以做到 discovery everything,所有配置都可以通过发现的方式解决,这是 Envoy xDS 架构为微服务世界带来的重大变革。
xDS 概念介绍
xDS 包含:
- LDS(监听器发现服务)
- CDS(集群发现服务)
- EDS(节点发现服务)
- SDS(密钥发现服务)
- RDS(路由发现服务)
xDS 中每种类型对应一个发现的资源,这些类型数据存储在 xDS 协议的 Discovery Request 和 Discovery Response 的 TypeUrl 字段中, 这个字段按照以下格式存储: type.googleapis.com/<resource type>
eg: type.googleapis.com/envoy.api.v2.Cluster 就表明是 Cluster 类型的资源,需要按照 Cluster 类型处理数据
LDS
envoy.api.v2.Listener(LDS):对应 Listener 数据类型,包含了监听器的名称、监听端口、监听地址等信息,通过动态更新此类型,可以动态新增监听器或者更新监听器的地址端口等信息。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22{
"name": "...",
"address": "{...}",
"filter_chains": [],
"use_original_dst": "{...}",
"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": []
}
RDS
envoy.api.v2.RouteConfiguration(RDS):对应 Envoy 中的 Route 类型,用于更新 virtual_hosts,以及 virtual_hosts 包含的路由表信息、路由规则、针对路由的限流、路由级别的插件等,包括路由匹配到的 Cluster。1
2
3
4
5
6
7
8
9
10
11
12{
"name": "...",
"virtual_hosts": [],
"vhds": "{...}",
"internal_only_headers": [],
"response_headers_to_add": [],
"response_headers_to_remove": [],
"request_headers_to_add": [],
"request_headers_to_remove": [],
"most_specific_header_mutations_wins": "...",
"validate_clusters": "{...}"
}
CDS
envoy.api.v2.Cluster(CDS):对应 Envoy 中的 Cluster 类型,包含了 Cluster 是采用静态配置数据,还是采用动态 EDS 发现的方式,包括 Cluster 的负载均衡策略、健康检查配置等,以及服务级别的插件设置
1 | { |
EDS
envoy.api.v2.ClusterLoadAssignment(EDS) :常说的服务发现。包含服务名、节点信息和 LB 策略等数据。1
2
3
4
5{
"cluster_name": "...",
"endpoints": [],
"policy": "{...}"
}
SDS
envoy.api.v2.Auth.Secret(SDS):用于发现证书信息,以动态更新证书。
istio 可以通过 SDS 即可动态更新证书
{
“name”: “…”,
“tls_certificate”: “{…}”,
“session_ticket_keys”: “{…}”,
“validation_context”: “{…}”,
“generic_secret”: “{…}”
}
gRPC 流式订阅
1 | grpcurl -v -plaintext admin-rpc-service.eve-cn-infra-dev:30200 list |
需要给 grpc 的 svc 添加appProtocol: http2
参考链接 https://istio.io/latest/docs/ops/configuration/traffic-management/protocol-selection/
1 | for svc in \ |
API 请求顺序
典型的 HTTP 路由场景,客户端需要先获取 Listener 资源,通过 Listener 资源拿到 Route 的配置。Route 中包含一个或者多个 Cluster 集群资源,通过 Cluster 集群的信息再获取集群节点的信息,这样整个请求链路就完成了
全量请求和增量请求
当出现新的资源时,只需向 Management Server 发送新增的资源,Management Server 也只会返回新增资源的数据。
多条请求流和单条请求流
xDS 协议并不约束在请求多个资源时,多个资源使用同一个请求流,还是每个资源各使用一个请求流,Management Server 应该同时支持这两种模式。
在一个连接请求多个资源
支持在一条连接中按照顺序获取 xDS 中的各种 API,比如先请求 CDS,然后请求 EDS
xDS 协议详解
请求信息示例:1
2
3
4
5
6
7version_info: # version_info 为空,表示这是连接中的第一个请求流
node: { id: envoy } # Node 中的 ID 则表明机器信息,需要传递机器的唯一标识
resource_names:
- foo
- bar
type_url: type.googleapis.com/envoy.api.v2.ClusterLoadAssignment # EDS
response_nonce:
回应信息示例:1
2
3
4
5
6version_info: X
resources:
- foo ClusterLoadAssignment proto encoding
- bar ClusterLoadAssignment proto encoding
type_url: type.googleapis.com/envoy.api.v2.ClusterLoadAssignment
nonce: A # ACK NACK 或者区分资源更新到底是响应哪个推送数据。
补
在收到 Management Server 推送的新版本数据后,Envoy 会响应 ACK 或者 NACK 告知 Management Server 是否更新版本成功。ACK 代表更新版本成功,这时会携带 Management Server 推送的最新版本号发送 ACK 信息;NACK 代表更新版本失败,这时会携带旧的版本号发送 NACK 信息。
补 边缘代理模式
Envoy 不仅可以用于 Sidecar 模式,也可以用作边缘网关,但是用作边缘网关层我们有一些注意事项,这些问题不仅在 Envoy 中存在,在其他的边缘网关中也应该处理。
- HTTP 标头清理 : use_remote_address 设置为 true 来清理 HTTP 标头。
- 超时控制 : 连接超时、流超时和路由超时。
- 连接限制