Envoy代理深度配置:构建高性能API网关

深入讲解Envoy代理的核心概念与高级配置,详解Listener、Cluster、Route、Filter等组件,提供流量管理、故障注入、访问日志、gRPC转码等生产级配置示例。

引言

Envoy是Cloud Native Computing Foundation(CNCF)的毕业项目,作为L7代理和通信总线,被广泛应用于Service Mesh和API网关场景。自2016年由Lyft开源以来,Envoy已迅速成长为云原生生态系统中最为关键的流量管控基础设施组件之一。无论是Kubernetes集群中的Ingress控制器,还是像Istio这样的服务网格数据面,还是大型互联网企业构建的七层流量网关,Envoy都以其卓越的性能表现和高度可扩展的架构,撑起了整个生态的流量治理骨架。

本文将深入讲解Envoy的核心配置和高级用法,从最基础的最小化配置出发,逐步深入HTTP连接管理、四级配置模型、安全加固、可观测性集成、高级流量管理和性能调优等生产级话题。所有配置示例均经过验证,读者可以直接复制到本地环境中进行测试。

Envoy核心概念

理解Envoy的关键在于掌握其配置的整体层级架构。Envoy采用自上而下四级配置模型,每一层清晰分工,通过xDS协议支持全量或增量的动态更新,这使得Envoy可以在不重启进程的前提下零损热加载配置。

四级配置模型

Envoy配置层级:

┌─────────────────────────────────────┐
│           Admin Interface           │  管理接口(9901端口,stats/debug)
├─────────────────────────────────────┤
│              Listeners              │  监听器(接收连接,绑定端口)
├─────────────────────────────────────┤
│          Filter Chains              │  过滤器链(处理请求的核心流水线)
├─────────────────────────────────────┤
│               Routes                │  路由规则(匹配路径与下游集群)
├─────────────────────────────────────┤
│              Clusters               │  集群(后端服务抽象,含负载均衡)
├─────────────────────────────────────┤
│             Endpoints               │  端点(具体实例地址与权重)
└─────────────────────────────────────┘

Listener负责在网络层面接收客户端的连接请求,并为每个连接匹配一条Filter Chain。Filter Chain中按顺序排列多个Filter,其中HTTP Connection Manager(HCM)是处理七层HTTP流量的核心过滤器。HCM内部维护独立的路由表,通过Route将请求映射到对应的Cluster,最终由Cluster管理的一组Endpoint实际承载请求转发。

xDS动态配置协议

Envoy通过xDS API与外部的控制平面(如Istio Pilot、Go Control Plane)交互,实现对配置的全动态管理。xDS家族包含以下核心协议:

  • LDS(Listener Discovery Service):动态推送Listener配置。
  • RDS(Route Discovery Service):动态推送Route路由规则。
  • CDS(Cluster Discovery Service):动态推送Cluster后端集群配置。
  • EDS(Endpoint Discovery Service):动态推送Endpoint端点信息。
  • ADS(Aggregated Discovery Service):单一gRPC流聚合所有xDS资源,避免资源更新顺序依赖带来的不一致问题。

在生产环境中,强烈建议使用ADS聚合流统一推送所有配置,以保证Listener与Route之间、Route与Cluster之间的引用关系始终保持原子一致性,避免短时间内的配置断层。

基础配置

最小化配置示例

以下是一个最精简但可直接启动的Envoy配置文件,它监听在10000端口,将所有HTTP流量转发到后端服务集群。

# envoy.yaml
static_resources:
  listeners:
    - name: listener_0
      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: service_backend
                
                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  
  clusters:
    - name: service_backend
      connect_timeout: 0.25s
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: service_backend
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: backend-service
                      port_value: 8080

admin:
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9901

将上述配置保存为envoy.yaml,通过如下Docker命令即可启动Envoy服务:

docker run --rm -it \
  -p 10000:10000 \
  -p 9901:9901 \
  -v $(pwd)/envoy.yaml:/etc/envoy/envoy.yaml \
  envoyproxy/envoy:v1.29.0 \
  -c /etc/envoy/envoy.yaml

启动成功后,你可以通过curl http://localhost:10000/验证流量是否被正常代理到后端服务,同时通过curl http://localhost:9901/stats/prometheus获取Prometheus格式的原始指标。

Envoy架构与核心概念深度解析

HTTP Connection Manager(HCM)Filter Chain

Envoy的网络模型允许一个Listener绑定多条Filter Chain,每条Chain通过filter_chain_match条件(如SNI、源IP、目的端口等)精确匹配。对于HTTP流量,最常用的过滤器链入口是HttpConnectionManager,它完整接管HTTP/1.1和HTTP/2协议解析,并向下游的HTTP Filter链分发请求。

listeners:
  - name: listener_https
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 443
    listener_filters:
      - name: envoy.filters.listener.tls_inspector
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
    filter_chains:
      - filter_chain_match:
          server_names: ["api.example.com"]
        transport_socket:
          name: envoy.transport_sockets.tls
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
            common_tls_context:
              tls_certificate_sds_secret_configs:
                - name: api_example_com_cert
                  sds_config:
                    path: /etc/envoy/sds/api_cert.yaml
        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_https
              codec_type: AUTO
              http_protocol_options:
                enable_trailers: true
              http2_protocol_options:
                max_concurrent_streams: 100
                initial_stream_window_size: 65536
              stream_idle_timeout: 300s
              request_timeout: 300s
              drain_timeout: 5s
              route_config:
                name: https_routes
                virtual_hosts:
                  - name: api_vhost
                    domains: ["api.example.com"]
                    routes:
                      - match:
                          prefix: "/"
                        route:
                          cluster: api_cluster
                          timeout: 30s
              http_filters:
                - name: envoy.filters.http.cors
                  typed_config:
                    "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
                - name: envoy.filters.http.router
                  typed_config:
                    "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

此配置展示了基于TLS SNI匹配的多域名支持。tls_inspector监听器过滤器在进入主过滤器链前解析TLS握手元数据,从而实现同端口多证书的精细化路由。codec_type: AUTO让Envoy自动在HTTP/1.1和HTTP/2之间协商,极大简化了运维负担。

HTTP连接管理与超时配置

生产环境的超时策略如果配置不当可能导致级联雪崩。Envoy在时间控制层面提供了丰富的粒度,从连接到流、到请求路由、再到重试试次均有独立超时参数。以下是一个经过生产验证的超时配置示例:

typed_config:
  "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
  common_http_protocol_options:
    idle_timeout: 3600s
    headers_with_underscores_action: REJECT_REQUEST
  http_protocol_options:
    enable_trailers: true
    accept_http_10: true
  http2_protocol_options:
    max_concurrent_streams: 100
    initial_stream_window_size: 65536
    initial_connection_window_size: 1048576
  stream_idle_timeout: 300s
  request_timeout: 300s
  drain_timeout: 30s
  delayed_close_timeout: 1s

关键超时参数的语义如下:stream_idle_timeout检测单个HTTP流在两次数据帧之间是否超过静默阈值,适用于防止慢攻击;request_timeout涵盖整个请求生命周期,从请求头接收完毕到响应体完全发送;drain_timeout在连接排水期间确保存量请求正常结束。headers_with_underscores_action: REJECT_REQUEST则是一项重要的安全加固手段,能够拦截利用Header名称混淆发起的协议层攻击。

高级路由配置

基于Header的路由

现代微服务发布策略中,金丝雀发布(Canary)和蓝绿部署高度依赖基于Header的流量切分能力。Envoy的路由匹配器支持对Header进行精确匹配、前缀匹配、正则匹配以及基于范围的匹配,足以覆盖绝大多数灰度发布场景。

route_config:
  name: advanced_routing
  virtual_hosts:
    - name: api_service
      domains: ["api.example.com"]
      routes:
        # 基于Header路由到Canary版本
        - match:
            prefix: "/api/v1/users"
            headers:
              - name: x-canary
                exact_match: "true"
          route:
            cluster: user_service_canary
            timeout: 30s
        
        # 基于Header路由到特定版本
        - match:
            prefix: "/api/"
            headers:
              - name: x-api-version
                exact_match: "v2"
          route:
            cluster: api_service_v2
        
        # 默认路由
        - match:
            prefix: "/api/"
          route:
            cluster: api_service_v1
            retry_policy:
              retry_on: "5xx,connect-failure,reset"
              num_retries: 3
              per_try_timeout: 10s
              retry_back_off:
                base_interval: 0.25s
                max_interval: 1s

在此配置中,金丝雀Header的优先级高于版本Header,因为Envoy按路由列表顺序自上而下匹配,第一条匹配成功即停止搜索。生产系统的最佳实践是将最细粒度的匹配规则放在列表前端,默认兜底规则放在尾部。

加权路由(流量分割)

A/B测试场景中,通过weighted_clusters将流量按比例分配到不同版本的后端集群是一种无侵入的发布方式。

route_config:
  virtual_hosts:
    - name: payment_service
      domains: ["payment.example.com"]
      routes:
        - match:
            prefix: "/process"
          route:
            weighted_clusters:
              clusters:
                - name: payment_v1
                  weight: 90
                - name: payment_v2
                  weight: 10
              total_weight: 100
              runtime_key_prefix: routing.payment

增加runtime_key_prefix后,可以通过Envoy的运行时接口动态调整权重而无需重新加载配置。例如执行curl -X POST "localhost:9901/runtime_modify?routing.payment.payment_v1=80&routing.payment.payment_v2=20"即可实时切换流量比例。

路由重写与重定向

routes:
  # URL重写
  - match:
      prefix: "/old-api/"
    route:
      cluster: new_api_service
      prefix_rewrite: "/api/v2/"
  
  # 正则重写
  - match:
      safe_regex:
        regex: "^/users/([0-9]+)/profile$"
    route:
      cluster: user_service
      regex_rewrite:
        pattern:
          google_re2: {}
          regex: "^/users/([0-9]+)/profile$"
        substitution: "/api/users/\\1"
  
  # 重定向
  - match:
      prefix: "/legacy/"
    redirect:
      prefix_redirect: "/modern/"
      response_code: MOVED_PERMANENTLY  # 301

正则重写利用了Google RE2引擎,因此表达式需符合RE2语法约束。通过正则匹配,可以实现类似RESTful风格的URL重构,将旧版路径透明映射到新服务接口。

Cluster高级配置

熔断器(Circuit Breaker)

熔断器是防止下游故障引发级联雪崩的最后一道防线。Envoy的熔断器支持对每个Cluster按优先级分别控制最大连接数、最大挂起请求数、最大并发请求数和最大重试次数。当任何一项阈值被突破时,Envoy将快速失败,直接向上游返回错误码,避免让已经过载的后端服务雪上加霜。

clusters:
  - name: order_service
    connect_timeout: 0.5s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    circuit_breakers:
      thresholds:
        - priority: DEFAULT
          max_connections: 1024
          max_pending_requests: 1024
          max_requests: 1024
          max_retries: 3
          track_remaining: true
          retry_budget:
            budget_percent:
              value: 25.0
            min_retry_concurrency: 10
        - priority: HIGH
          max_connections: 2048
          max_pending_requests: 2048
          max_requests: 2048
    
    # 异常检测(自动剔除故障节点)
    outlier_detection:
      consecutive_5xx: 5
      interval: 10s
      base_ejection_time: 30s
      max_ejection_percent: 50
      enforcing_consecutive_5xx: 100
      enforcing_success_rate: 100
      success_rate_minimum_hosts: 3
      success_rate_request_volume: 100
      success_rate_stdev_factor: 1900
    
    load_assignment:
      cluster_name: order_service
      endpoints:
        - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: order-1
                    port_value: 8080
              load_balancing_weight: 100
            - endpoint:
                address:
                  socket_address:
                    address: order-2
                    port_value: 8080
              load_balancing_weight: 100

track_remaining: true允许Envoy暴露remaining_cx、remaining_rq等指标,配合Prometheus可以实时监控熔断器的使用余量。retry_budget引入了基于预算的重试策略,突破了传统固定重试次数的限制,使得重试比例能够根据实际请求量自适应调整。

健康检查

主动健康检查让Envoy能够持续探测后端实例的实际可用性,结合被动异常检测可以实现趋于完美的故障节点自动剔除与恢复。

clusters:
  - name: backend_service
    connect_timeout: 1s
    type: STRICT_DNS
    lb_policy: LEAST_REQUEST
    least_request_lb_config:
      choice_count: 2  # Power of Two Choices算法
      active_request_bias:
        runtime_key: least_request_active_request_bias
        default_value: 1.0
    
    health_checks:
      - timeout: 5s
        interval: 10s
        initial_jitter: 1s
        unhealthy_threshold: 3
        healthy_threshold: 2
        http_health_check:
          path: "/health"
          expected_statuses:
            - start: 200
              end: 200
          request_headers_to_add:
            - header:
                key: "x-health-check"
                value: "envoy"
        event_log_path: "/dev/stdout"
    
    upstream_bind_config:
      source_address:
        address: 0.0.0.0
        port_value: 0

LEAST_REQUEST负载均衡策略配合choice_count: 2即经典的"两权取轻"算法,在大规模后端实例场景下既保证了负载分散的均匀性,又将排序复杂度降到非常低的水平。健康检查的事件日志路径设置为标准输出,便于结合容器日志收集系统进行统一分析。

Filter配置

速率限制

Envoy支持与外部的速率限制服务(如Lyft开源的ratelimit)协同工作,实现细粒度的请求限流控制。以下配置将每条请求的关键描述符发送到限流服务进行计数决策。

http_filters:
  - name: envoy.filters.http.ratelimit
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
      domain: api_gateway
      stage: 0
      timeout: 0.5s
      failure_mode_deny: false
      rate_limit_service:
        grpc_service:
          envoy_grpc:
            cluster_name: ratelimit_service
          timeout: 0.25s
        transport_api_version: V3
      enable_x_ratelimit_headers: DRAFT_VERSION_03
  
  - name: envoy.filters.http.router
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

enable_x_ratelimit_headers: DRAFT_VERSION_03会向客户端响应中添加x-ratelimit-limit、x-ratelimit-remaining、x-ratelimit-reset等标准化Header,方便前端和消费方实现友好的限流提示。

CORS配置

跨域资源共享(CORS)策略直接由Envoy在边缘层处理,避免了后端服务重复实现CORS逻辑的可维护性问题。

http_filters:
  - name: envoy.filters.http.cors
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors

# 在virtual_hosts中配置CORS策略
virtual_hosts:
  - name: api
    domains: ["api.example.com"]
    cors:
      allow_origin_string_match:
        - exact: "https://www.example.com"
        - prefix: "https://"
          suffix: ".example.com"
      allow_methods: "GET, POST, PUT, DELETE, OPTIONS"
      allow_headers: "Content-Type, Authorization, X-Request-ID, X-Correlation-ID"
      expose_headers: "X-Request-ID, X-RateLimit-Remaining"
      max_age: "3600"
      allow_credentials: true
      filter_enabled:
        runtime_key: cors_filter_enabled
        default_value:
          numerator: 100
          denominator: HUNDRED
      filter_enabled_metadata:
        filter: envoy.filters.http.cors
        path:
          - key: cors_proxy
        value:
          bool_match: true

JWT认证

Envoy原生支持JWT认证,无需额外部署Sidecar即可在网关层面完成身份校验,将认证压力从业务服务中剥离。

http_filters:
  - name: envoy.filters.http.jwt_authn
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
      providers:
        auth0_provider:
          issuer: "https://your-domain.auth0.com/"
          audiences:
            - "https://api.example.com"
          remote_jwks:
            http_uri:
              uri: "https://your-domain.auth0.com/.well-known/jwks.json"
              cluster: auth0_cluster
              timeout: 1s
            cache_duration:
              seconds: 300
          forward: true
          forward_payload_header: "x-jwt-payload"
          from_headers:
            - name: Authorization
              value_prefix: "Bearer "
      rules:
        - match:
            prefix: "/api/public"
        - match:
            prefix: "/api/"
          requires:
            provider_name: auth0_provider

forward_payload_header将解码后的JWT Payload以Base64编码形式透传给后端服务,使后端无需重复解码Token即可获得用户身份信息。

安全加固

TLS终端与mTLS双向认证

在公网网关场景下,TLS加密是底线要求。更进一步,当Envoy作为服务网格Sidecar使用时,需要通过mTLS实现服务间的双向身份校验,确保即使是Pod内部的横向流量也处于加密与认证保护之下。

clusters:
  - name: secure_backend
    connect_timeout: 1s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        common_tls_context:
          tls_certificate_sds_secret_configs:
            - name: client_cert
              sds_config:
                path: /etc/envoy/sds/client_cert.yaml
          validation_context_sds_secret_config:
            name: server_ca
            sds_config:
              path: /etc/envoy/sds/server_ca.yaml
          tls_params:
            tls_minimum_protocol_version: TLSv1_2
            cipher_suites:
              - "ECDHE-RSA-AES128-GCM-SHA256"
              - "ECDHE-RSA-AES256-GCM-SHA384"
    load_assignment:
      cluster_name: secure_backend
      endpoints:
        - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: secure-backend
                    port_value: 8443

tls_minimum_protocol_version: TLSv1_2强制禁用所有TLSv1.0和TLSv1.1连接,消除已知的老版本协议漏洞。通过SDS(Secret Discovery Service)动态加载证书,可以在证书轮换期间实现TLS信任的平滑更新,无需重启Envoy进程。

RBAC访问控制

RBAC过滤器允许基于请求属性进行细粒度的授权决策,包括源IP范围、JWT声明、请求路径、HTTP方法等维度,实现网关层的统一鉴权。

http_filters:
  - name: envoy.filters.http.rbac
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC
      rules:
        action: ALLOW
        policies:
          "admin-access":
            permissions:
              - any: true
            principals:
              - header:
                  name: "x-role"
                  exact_match: "admin"
          "user-readonly":
            permissions:
              - url_path:
                  path:
                    prefix: "/api/v1/users"
              - method: GET
            principals:
              - header:
                  name: "x-role"
                  exact_match: "user"
          "public-health":
            permissions:
              - url_path:
                  path:
                    exact: "/health"
            principals:
              - any: true
      shadow_rules:
        action: DENY
        policies:
          "shadow-deny":
            permissions:
              - url_path:
                  path:
                    prefix: "/internal"
            principals:
              - any: true
  
  - name: envoy.filters.http.router
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

shadow_rules是一项极具实用价值的审计特性,它不会实际拦截请求,但会统计影子规则命中的次数并输出到Access Log中。运维人员可以通过影子模式先行评估新策略的影响面,确认无误后再将规则从shadow迁移到正式rules。

可观测性集成

结构化访问日志

统一且结构化的访问日志是现代可观测性体系的基石。Envoy原生支持JSON格式的访问日志输出,字段完全可定制,并且能够无缝接入ELK、Loki等各种日志收集与分析平台。

http_connection_manager:
  access_log:
    - name: envoy.access_loggers.file
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
        path: "/dev/stdout"
        log_format:
          json_format:
            timestamp: "%START_TIME%"
            method: "%REQ(:METHOD)%"
            path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
            protocol: "%PROTOCOL%"
            response_code: "%RESPONSE_CODE%"
            response_flags: "%RESPONSE_FLAGS%"
            bytes_received: "%BYTES_RECEIVED%"
            bytes_sent: "%BYTES_SENT%"
            duration: "%DURATION%"
            upstream_service_time: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"
            upstream_host: "%UPSTREAM_HOST%"
            request_id: "%REQ(X-REQUEST-ID)%"
            user_agent: "%REQ(USER-AGENT)%"
            trace_id: "%REQ(X-B3-TRACEID)%"
            authority: "%REQ(:AUTHORITY)%"
            upstream_cluster: "%UPSTREAM_CLUSTER%"
            connection_termination_details: "%CONNECTION_TERMINATION_DETAILS%"
            grpc_status: "%GRPC_STATUS%"
  
  tracing:
    provider:
      name: envoy.tracers.zipkin
      typed_config:
        "@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig
        collector_cluster: zipkin
        collector_endpoint: "/api/v2/spans"
        collector_endpoint_version: HTTP_JSON
        shared_span_context: true

Prometheus指标暴露

Envoy在Admin端口9901上提供了Prometheus原生格式的指标端点,无需额外Exporter即可被Prometheus直接抓取。常用的核心指标包括:

  • envoy_cluster_upstream_rq_total:上游请求总数
  • envoy_cluster_upstream_rq_time_bucket:上游请求延迟直方图
  • envoy_http_downstream_rq_total:下游请求总数
  • envoy_cluster_circuit_breakers_default_open:熔断器开启状态
  • envoy_cluster_outlier_detection_ejections_active:当前被剔除的异常节点数

OpenTelemetry Tracing配置

相比传统的Zipkin或Jaeger,OpenTelemetry正逐渐成为分布式追踪领域的事实标准。以下配置展示了Envoy接入OpenTelemetry Collector的方式:

tracing:
  provider:
    name: envoy.tracers.opentelemetry
    typed_config:
      "@type": type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig
      grpc_service:
        envoy_grpc:
          cluster_name: opentelemetry_collector
        timeout: 0.25s
      service_name: envoy-gateway

Envoy产生的Span将与后端服务产生的Span汇聚在同一Trace中,通过x-request-id或W3C Trace Context进行跨服务传播,形成端到端的请求调用链全景图。

高级流量管理

全局速率限制与局部速率限制

局部速率限制filter在Envoy进程本地进行计数,不需要外部依赖,适合对全局限流精度要求不高但需要极低延迟的场景。全局速率限制则通过与ratelimit服务交互实现分布式限流,适合多实例网关共享配额的情形。

http_filters:
  - name: envoy.filters.http.local_ratelimit
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
      stat_prefix: local_rate_limit
      token_bucket:
        max_tokens: 10000
        tokens_per_fill: 1000
        fill_interval: 1s
      filter_enabled:
        runtime_key: local_rate_limit_enabled
        default_value:
          numerator: 100
          denominator: HUNDRED
      filter_enforced:
        runtime_key: local_rate_limit_enforced
        default_value:
          numerator: 100
          denominator: HUNDRED
      response_headers_to_add:
        - append_action: OVERWRITE_IF_EXISTS_OR_ADD
          header:
            key: x-local-rate-limit
            value: 'true'
      descriptors:
        - entries:
            - key: path
              value: "/api/v1/expensive"
          token_bucket:
            max_tokens: 100
            tokens_per_fill: 10
            fill_interval: 1s

流量镜像

流量镜像(Traffic Mirroring)允许将生产流量无损复制到预发布或新版本集群,而不会影响原请求的响应延迟和成功率。被镜像的请求的响应会被Envoy直接丢弃,原请求的用户对此完全无感知。

routes:
  - match:
      prefix: "/api/"
    route:
      cluster: production_service
      request_mirror_policies:
        - cluster: shadow_service
          runtime_fraction:
            default_value:
              numerator: 10
              denominator: HUNDRED
            runtime_key: shadow_mirror_percent
          trace_sampled: false

此配置将百分之十的生产流量镜像到shadow_service集群。开发者通过观察影子集群的延迟分布、错误率和资源消耗,可以在正式全量上线前获得新版本在真实流量下的表现数据。

故障注入

在混沌工程实践中,故障注入是验证系统韧性的有效手段。Envoy的HTTP Fault Filter支持按照指定百分比注入延迟和故障,是service mesh中实施混沌实验的基础设施。

http_filters:
  - name: envoy.filters.http.fault
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
      abort:
        http_status: 503
        percentage:
          numerator: 10
          denominator: HUNDRED
      delay:
        fixed_delay: 2s
        percentage:
          numerator: 20
          denominator: HUNDRED
      upstream_cluster:
        cluster_name: order_service
      headers:
        - name: x-envoy-fault
          exact_match: "true"
      max_active_faults: 100
      response_rate_limit:
        fixed_limit:
          limit_kbps: 1024
        percentage:
          numerator: 50
          denominator: HUNDRED

max_active_faults限制了同时生效的故障注入数量,避免故障实验本身因为过量注入而演变为生产事故。response_rate_limit还可以对响应带宽进行限流,模拟慢速网络环境。

gRPC转码

gRPC-Web支持

浏览器端JavaScript无法直接发起gRPC调用,因为浏览器不支持HTTP/2的 trailers和必要的二进制帧流控。Envoy的gRPC-Web过滤器承担了协议转换的职责,使得前端可以通过gRPC-Web客户端与后端gRPC服务透明通信。

http_filters:
  - name: envoy.filters.http.grpc_web
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
  
  - name: envoy.filters.http.cors
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
  
  - name: envoy.filters.http.router
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

clusters:
  - name: grpc_service
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}  # 启用HTTP/2
    load_assignment:
      cluster_name: grpc_service
      endpoints:
        - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: grpc-backend
                    port_value: 50051

REST到gRPC转码

对于已经基于gRPC构建后端服务、但前端或第三方客户坚持使用REST JSON风格的团队,gRPC JSON Transcoder是一个理想的折中方案。

http_filters:
  - name: envoy.filters.http.grpc_json_transcoder
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder
      proto_descriptor: "/etc/envoy/proto_descriptor.pb"
      services:
        - "bookstore.BookstoreService"
      print_options:
        add_whitespace: true
        always_print_primitive_fields: true
        always_print_enums_as_ints: false
        preserve_proto_field_names: false
      convert_grpc_status: true
      auto_mapping: true
// bookstore.proto
syntax = "proto3";

package bookstore;

import "google/api/annotations.proto";

service BookstoreService {
  rpc GetBook(GetBookRequest) returns (Book) {
    option (google.api.http) = {
      get: "/v1/shelves/{shelf}/books/{book}"
    };
  }
  
  rpc CreateBook(CreateBookRequest) returns (Book) {
    option (google.api.http) = {
      post: "/v1/shelves/{shelf}/books"
      body: "book"
    };
  }
  
  rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {
    option (google.api.http) = {
      get: "/v1/shelves/{shelf}/books"
    };
  }
}

proto_descriptor.pb文件需要通过protoc工具配合google/api/annotations.proto与google/api/http.proto提前编译生成。将编译后的描述符文件挂载到Envoy容器中,即可实现JSON与Protobuf之间的自动双向转码。

性能调优

工作线程与连接池参数

Envoy的高性能很大程度上源于其多线程无锁架构,每个工作线程独立运行事件循环。合理的工作线程和连接池参数能够显著影响资源利用率和P99延迟表现。

# 启动参数
--concurrency 4 \
--cpuset-threads \
--enable-fine-grain-logging

# cluster中的连接池配置
clusters:
  - name: optimized_backend
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    upstream_connection_options:
      tcp_keepalive:
        keepalive_time: 300
        keepalive_interval: 75
        keepalive_probes: 9
    circuit_breakers:
      thresholds:
        - priority: DEFAULT
          max_connections: 1000
          max_pending_requests: 1000
          max_requests: 1000
    common_http_protocol_options:
      idle_timeout: 3600s
    http_protocol_options:
      enable_trailers: true
    typed_extension_protocol_options:
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
        upstream_protocol_options:
          explicit_http_config:
            http2_protocol_options:
              max_concurrent_streams: 100
              initial_stream_window_size: 65536
              initial_connection_window_size: 1048576

--concurrency参数定义了Envoy工作线程的数量,默认自动设置为机器的核心数。在容器化环境中,建议显式设置为容器CPU限额对应的核数,避免调度抖动。TCP Keepalive参数确保空闲长连接不会因为NAT网关或云厂商负载均衡器的静默超时而被意外断开。

热重启机制

Envoy的热重启机制可以在不丢包、不拒绝连接的前提下完成二进制升级和配置重载。通过父子进程间的共享内存和Unix Domain Socket传递监听器文件描述符,Envoy实现了平滑过渡。

# 执行热重启
envoy -c /etc/envoy/envoy.yaml --restart-epoch 1

# 或者通过admin接口热更新配置
curl -X POST "http://localhost:9901/runtime_modify?key1=val1&key2=val2"
curl -X POST "http://localhost:9901/config_dump"
curl -X POST "http://localhost:9901/clusters"

在Kubernetes环境中,利用preStop生命周期钩子调用排水端点curl -X POST http://localhost:9901/drain_listeners?graceful,并设置合理的terminationGracePeriodSeconds,可以让Pod在缩容或滚动更新期间完成存量请求的优雅处理。

总结

Envoy以其灵活的架构设计和丰富的L7功能,成为云原生时代流量治理的事实标准基础设施。本文从最基础的最小化配置出发,逐步深入到HTTP连接管理、四级配置模型、安全加固、可观测性集成、高级流量管理和性能调优等各个维度,提供了可直接运行的生产级配置示例。

综合全文,构建一个健壮且高性能的Envoy API网关需要遵循以下最佳实践:

  1. 模块化配置:在生产环境中彻底摒弃static_resources的静态配置方式,全面采用xDS API动态管理所有资源。通过ADS聚合流保障Listener、Route和Cluster之间的引用一致性。

  2. 熔断保护:为所有业务Cluster配置合理的circuit breakers阈值,并结合outlier_detection实现故障节点的自动检测与隔离。熔断配置应与实际业务容量相匹配,避免过于宽松失去保护意义,也避免过于严格导致正常流量被拒。

  3. 健康检查:同时启用主动健康检查和被动异常检测。主动探测提供最高置信度的节点可用性判断,被动统计则能在主动探测间隙及时发现异常节点。

  4. 可观测性 :配置结构化JSON格式的访问日志,集成Prometheus指标和OpenTelemetry分布式追踪,构建从日志到指标再到Trace的三位一体可观测体系。

  5. 安全加固:对外启用TLSv1.2及以上版本的加密传输,对内通过mTLS实现服务间双向认证。在网关层部署JWT和RBAC过滤器,将认证和鉴权压力从后端服务中剥离。

  6. 性能调优:根据容器CPU限额显式设置并发线程数,合理配置TCP Keepalive和HTTP/2流控窗口,善用热重启和优雅排水机制保障线上的滚动升级平滑无感。

关键优势:

  • 高性能(C++实现,零拷贝)
  • 丰富的L7功能
  • 云原生设计(xDS API)
  • 活跃的社区和生态

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「backend」更多文章

  1. 零信任安全架构:从边界防御到身份中心的安全范式
  2. 混沌工程实践:构建高可用系统的故障注入与弹性测试
  3. 流式数据处理:Kafka Streams与Flink实战指南