第4章:Envoy 代理深入:核心概念与 xDS 协议

好,咱们今天来啃一块硬骨头——Envoy 的核心概念。说实话,很多人在刚接触服务网格时,都被 Envoy 那一堆术语搞懵了。Listener、Cluster、Endpoint,还有那个听起来很唬人的 xDS 协议。别急,我一个一个给你拆开讲。

4.1 三大核心概念:Listener、Cluster、Endpoint

我个人习惯把 Envoy 理解成一个「智能邮局」。你想想看,邮局要正常工作,需要什么?首先得有个收信窗口(Listener),然后要知道信该送到哪个片区(Cluster),最后得知道具体送到哪栋楼哪个房间(Endpoint)。

4.1.1 Listener(监听器)

Listener 就是 Envoy 的「耳朵」。它负责监听某个端口,等待流量进来。我在项目中遇到过一个问题:有个团队把 Listener 配成了监听 0.0.0.0:80,结果所有流量都涌进来了,根本没法做精细化控制。

核心要点:Listener 定义了 Envoy 如何接收流量。你可以配置多个 Listener,每个监听不同的端口或 IP。

# 一个简单的 Listener 配置示例
listeners:
- name: my_listener
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8080
  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: my_cluster
        http_filters:
        - name: envoy.filters.http.router

嗯,这里要注意:Listener 的配置里,filter_chains 是个关键。它决定了流量进来后怎么处理。说白了,就是给流量「过安检」。

4.1.2 Cluster(集群)

Cluster 是 Envoy 的「通讯录」。它告诉 Envoy:你要把流量发到哪一组后端服务去。每个 Cluster 可以包含多个后端实例,也就是 Endpoint。

我的经验:Cluster 的负载均衡策略一定要根据业务场景选。我见过有人所有服务都用 ROUND_ROBIN,结果某个服务响应时间差异很大,导致部分请求超时。后来改成 LEAST_REQUEST 就好多了。

clusters:
- name: my_cluster
  connect_timeout: 0.25s
  type: STRICT_DNS
  dns_lookup_family: V4_ONLY
  lb_policy: LEAST_REQUEST
  load_assignment:
    cluster_name: my_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 的类型有几种:STATIC、STRICT_DNS、LOGICAL_DNS、EDS。我个人最常用的是 EDS(Endpoint Discovery Service),因为它能动态感知后端变化。你想想看,如果后端扩容了,EDS 能自动把新实例加进来,多省心。

4.1.3 Endpoint(端点)

Endpoint 就是具体的后端实例。它包含 IP 地址和端口。在 Kubernetes 环境下,Endpoint 通常对应一个 Pod 的 IP。

我曾经踩过的坑:有一次生产环境出了故障,排查了半天才发现是 Endpoint 的健康检查配置有问题。Envoy 默认的健康检查是主动探测,但如果后端服务响应慢,就会误判为不健康。后来我改成了被动健康检查(outlier detection),问题就解决了。

Endpoint 的配置其实很简单,但它的健康状态管理却很重要。Envoy 支持两种健康检查方式:

  • 主动健康检查:Envoy 定期向后端发送探测请求
  • 被动健康检查:根据实际请求的成功率来判断

我建议你把两者结合起来用。主动检查保证及时发现问题,被动检查防止误杀。

4.2 xDS 协议:Envoy 的「神经中枢」

好,核心概念讲完了。现在咱们聊聊 xDS。这个 xDS 到底是什么?说白了,它就是 Envoy 和控制面之间的通信协议。x 代表多种发现服务,比如 LDS(Listener Discovery Service)、CDS(Cluster Discovery Service)、EDS(Endpoint Discovery Service)等等。

为什么会需要 xDS?你想想看,如果每个 Envoy 实例都要手动配置,那几百个实例得配到猴年马月去。xDS 让控制面可以动态下发配置,Envoy 只需要「听话」就行。

4.2.1 xDS 的家族成员

缩写 全称 作用
LDS Listener Discovery Service 动态下发 Listener 配置
CDS Cluster Discovery Service 动态下发 Cluster 配置
EDS Endpoint Discovery Service 动态下发 Endpoint 列表
RDS Route Discovery Service 动态下发路由规则
SDS Secret Discovery Service 动态下发证书和密钥

我记得刚开始用 Istio 时,看到这些缩写头都大了。后来发现,其实它们的工作流程很简单:控制面通过 gRPC 流把配置推送给 Envoy,Envoy 收到后立即生效。

4.2.2 xDS 的工作流程

咱们用个例子来说明。假设你更新了 Istio 的 VirtualService,想改变流量路由。整个过程是这样的:

  1. 控制面(比如 Istiod)检测到配置变化
  2. 它通过 RDS 把新的路由规则推送给 Envoy
  3. Envoy 收到后,更新本地路由表
  4. 新的请求就按照新规则走了

整个过程是实时的,不需要重启 Envoy。这就是 xDS 的威力所在。

关键点:xDS 使用 gRPC 双向流进行通信。这意味着控制面可以主动推送,Envoy 也可以主动请求。这种设计保证了配置的实时性和一致性。

4.2.3 实际项目中的 xDS 配置

我在一个项目中遇到过这样的场景:需要动态调整某个服务的流量比例。当时用的是 Istio 的 VirtualService,底层其实就是通过 RDS 实现的。

# 一个简单的 VirtualService 示例
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: my-service
spec:
  hosts:
  - my-service
  http:
  - match:
    - headers:
        version:
          exact: v2
    route:
    - destination:
        host: my-service
        subset: v2
  - route:
    - destination:
        host: my-service
        subset: v1

这个配置下发后,Envoy 会通过 RDS 获取到新的路由规则。带有 version: v2 头的请求会走 v2 版本,其他请求走 v1 版本。

我的建议:在生产环境中,一定要给 xDS 配置超时和重试机制。我曾经遇到过控制面短暂不可用,导致 Envoy 拿不到配置的情况。后来加了重试和缓存,问题就解决了。

4.3 总结与避坑指南

好,咱们来捋一捋今天的内容。Envoy 的三大核心概念——Listener、Cluster、Endpoint,说白了就是「收流量、找目标、发请求」。xDS 协议则是让这一切变得动态和自动化。

最后,分享几个我踩过的坑:

  • Listener 端口冲突:多个 Listener 不要监听同一个端口,否则会报错
  • Cluster 类型选错:如果后端 IP 会变,别用 STATIC,用 EDS 或 STRICT_DNS
  • 健康检查配置不当:主动检查和被动检查要配合使用,别只依赖一种
  • xDS 超时设置:控制面和 Envoy 之间的 gRPC 连接要设置合理的超时

嗯,今天就到这儿。下一章咱们会深入聊聊 Envoy 的过滤器链,那才是真正好玩的东西。