4. Envoy深度解析:Envoy核心概念、Listener与Cluster、Filter链机制、xDS协议
好,咱们进入第四章。Envoy,这是整个服务网格的数据面核心。说白了,你前面学的Istio控制面再牛,最后干活儿的还是Envoy。今天我就带你把它扒开看看,里面到底是怎么转的。
4.1 Envoy的核心概念:它到底是个啥?
Envoy不是普通的反向代理。它是个七层网络代理,专门为云原生环境设计的。我刚开始接触它的时候,第一反应是“这不就是个Nginx吗?”后来发现,差远了。
Envoy有几个核心身份:
- L3/L4/L7代理:从TCP到HTTP/gRPC,它全管
- 可编程的Filter链:每个请求进来,走一串过滤器,像流水线一样
- 动态配置:通过xDS协议,配置可以热更新,不用重启
我个人习惯把Envoy理解成一个“可编程的流量路由器”。你给它配好Listener和Cluster,它就知道从哪接流量、往哪发流量。
核心要点:Envoy的配置模型是“向下监听,向上转发”。Listener负责接客,Cluster负责找后端。
4.2 Listener与Cluster:流量的一进一出
咱们先看Listener。Listener就是Envoy监听的端口或Unix Socket。比如你配一个Listener监听80端口,所有到80的流量就都进了Envoy。
一个典型的Listener配置长这样:
static_resources:
listeners:
- name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 80
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: service_cluster
http_filters:
- name: envoy.filters.http.router
你看,这个Listener做了三件事:
- 监听0.0.0.0:80
- 用HTTP连接管理器处理请求
- 把请求路由到
service_cluster这个Cluster
Cluster呢?它就是后端服务的集合。Envoy会把流量负载均衡到Cluster里的各个Endpoint上。
clusters:
- name: service_cluster
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 10.0.0.1
port_value: 8080
- endpoint:
address:
socket_address:
address: 10.0.0.2
port_value: 8080
这里我提个坑。我曾经在生产环境遇到过一个问题:Cluster的type配成了STATIC,结果后端扩容了,Envoy死活不认新Pod。后来改成STRICT_DNS或者EDS才解决。嗯,动态发现才是云原生的正确姿势。
小技巧:如果你用Kubernetes,Cluster类型建议用EDS(Endpoint Discovery Service),这样Pod上下线Envoy能自动感知。
4.3 Filter链机制:请求的流水线加工
Filter链,这是Envoy最灵活的地方。每个请求进来,会经过一串Filter,每个Filter可以做自己的事:解析、修改、拦截、转发。
Filter分两层:
- 网络层Filter(L4):处理原始TCP连接,比如TLS终止、TCP代理
- HTTP层Filter(L7):处理HTTP请求,比如路由、限流、故障注入
你想想看,这就像一条流水线。每个Filter是一个工位,请求从第一个工位走到最后一个。任何一个Filter说“停”,请求就停了。
我举个例子,一个常见的HTTP Filter链:
http_filters:
- name: envoy.filters.http.fault
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.Fault
abort:
http_status: 503
percentage:
numerator: 10
denominator: HUNDRED
- name: envoy.filters.http.router
这个配置的意思是:10%的请求直接返回503,剩下的走正常路由。我在做混沌工程的时候,就靠这个来模拟服务故障。
注意:Filter的顺序很重要!比如限流Filter必须在路由Filter之前,否则限流就失效了。我曾经因为顺序搞反,排查了半天。
4.4 xDS协议:Envoy的“神经中枢”
xDS,全称是“Discovery Service”。它是一组API的统称,包括:
- LDS:Listener Discovery Service,发现Listener配置
- RDS:Route Discovery Service,发现路由规则
- CDS:Cluster Discovery Service,发现Cluster配置
- EDS:Endpoint Discovery Service,发现后端实例
- SDS:Secret Discovery Service,发现证书
说白了,xDS就是Envoy和控制面之间的“对话协议”。控制面(比如Istiod)通过xDS把配置推给Envoy,Envoy收到后立即生效,不用重启。
我画个简单的流程:
控制面 (Istiod) --xDS--> Envoy
|
|-- LDS: "监听8080端口"
|-- RDS: "/api/* 路由到 service-a"
|-- CDS: "service-a 有3个实例"
|-- EDS: "实例IP: 10.0.0.1, 10.0.0.2, 10.0.0.3"
为什么xDS这么重要?因为它是动态配置的基础。没有xDS,你改个路由还得重启Envoy,这在生产环境是不可接受的。
我记得有一次,线上服务需要紧急切流量。我直接在控制面改了路由规则,几秒钟后所有Envoy都收到了新配置,流量就切过去了。整个过程零停机。这就是xDS的价值。
核心总结:Listener决定“从哪接”,Cluster决定“往哪发”,Filter链决定“怎么处理”,xDS决定“怎么动态更新”。这四个概念,就是Envoy的骨架。
4.5 实战:用Envoy做个简单的反向代理
光说不练假把式。咱们写个完整的Envoy配置,跑一个反向代理。
static_resources:
listeners:
- name: ingress
address:
socket_address:
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: backend
http_filters:
- name: envoy.filters.http.router
clusters:
- name: backend
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: backend
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: www.example.com
port_value: 80
这个配置做了啥?Envoy监听10000端口,所有请求都转发到www.example.com:80。你启动Envoy后,访问localhost:10000,就能看到example.com的内容。
嗯,这里要注意:type: STRICT_DNS会让Envoy定期解析域名,如果IP变了,它会自动更新。这就是动态发现的雏形。
动手试试:把type改成STATIC,然后改一下www.example.com的IP,看看Envoy会不会自动感知?答案是不会。这就是为什么生产环境要用xDS。
好了,Envoy的核心概念就讲到这里。下一章咱们会深入Istio,看看它怎么用Envoy来实现服务网格。到时候你会发现,理解了Envoy,Istio就懂了一半。