Envoy 当 API gateway:替代 nginx 的现代选择

起因

微服务架构需要 API gateway 做:

  • 路由(path → service)
  • LB
  • 限流 / 熔断
  • TLS termination
  • 鉴权(OIDC / API key)
  • observability (metrics / traces)

老办法 nginx + Lua / openresty,扩展靠 module / 第三方 script。
Envoy(Lyft 出,CNCF)是云原生 API gateway 标准:

  • xDS API 动态配置(控制面 push 配置)
  • 内置 metric / trace
  • HTTP/2 / HTTP/3 / gRPC 一等公民
  • Istio / Consul Service Mesh 底层用它

装 / 跑

docker run -d -p 10000:10000 \
    -v $(pwd)/envoy.yaml:/etc/envoy/envoy.yaml \
    envoyproxy/envoy:v1.30.0

最小配置

# 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:
                  virtual_hosts:
                    - name: backend
                      domains: ["*"]
                      routes:
                        - match: { prefix: "/" }
                          route: { cluster: backend_service }
                http_filters:
                  - name: envoy.filters.http.router

  clusters:
    - name: backend_service
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: backend_service
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address: { address: backend, port_value: 8080 }

监听 10000,转发到 backend:8080。

路由

routes:
  - match: { prefix: "/api/users" }
    route: { cluster: user_service }

  - match: { prefix: "/api/orders" }
    route: { cluster: order_service }

  - match:
      prefix: "/admin"
      headers:
        - name: x-internal-tool
          string_match: { exact: "true" }
    route: { cluster: admin_service }

  - match: { prefix: "/" }
    route: { cluster: web_frontend }

prefix / path / regex / header / query 匹配,路由到不同 cluster。

LB 策略

clusters:
  - name: api_service
    lb_policy: LEAST_REQUEST       # ROUND_ROBIN / LEAST_REQUEST / RANDOM / RING_HASH
    load_assignment:
      endpoints:
        - lb_endpoints:
            - endpoint: { address: { socket_address: { address: api-1, port_value: 8080 }}}
            - endpoint: { address: { socket_address: { address: api-2, port_value: 8080 }}}

LEAST_REQUEST 比 round-robin 更智能(少请求的 instance 接新请求)。

限流

http_filters:
  - name: envoy.filters.http.local_ratelimit
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
      stat_prefix: http_local_rate_limiter
      token_bucket:
        max_tokens: 100
        tokens_per_fill: 100
        fill_interval: 1s
      filter_enabled:
        runtime_key: local_rate_limit_enabled
        default_value: { numerator: 100 }
      filter_enforced:
        runtime_key: local_rate_limit_enforced
        default_value: { numerator: 100 }

每秒 100 req,超出 429。

或者全局限流(多 envoy 共享)→ 外接 rate limit service(如 lyft/ratelimit)。

熔断

clusters:
  - name: backend
    circuit_breakers:
      thresholds:
        - max_connections: 100
        - max_pending_requests: 50
        - max_requests: 100
        - max_retries: 3

backend 慢 / 死 → envoy 主动拒新请求(避免雪崩)。

retry

routes:
  - match: { prefix: "/" }
    route:
      cluster: backend
      retry_policy:
        retry_on: "5xx,reset,connect-failure"
        num_retries: 3
        per_try_timeout: 5s

5xx / connection reset 自动重试 3 次。
对 idempotent 请求安全;POST / 写要小心。

TLS

listeners:
  - address:
      socket_address: { address: 0.0.0.0, port_value: 443 }
    filter_chains:
      - transport_socket:
          name: envoy.transport_sockets.tls
          typed_config:
            common_tls_context:
              tls_certificates:
                - certificate_chain: { filename: /etc/certs/cert.pem }
                  private_key: { filename: /etc/certs/key.pem }

ALPN / SNI 自动。HTTP/2 自动协商。

HTTP/3 / QUIC 也支持(额外配 udp_listener_config)。

鉴权:OAuth2 / JWT

http_filters:
  - name: envoy.filters.http.jwt_authn
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
      providers:
        my_provider:
          issuer: https://auth.example.com
          remote_jwks:
            http_uri:
              uri: https://auth.example.com/.well-known/jwks.json
              cluster: jwks_cluster
              timeout: 5s
            cache_duration: 600s
          forward: true
      rules:
        - match: { prefix: "/api" }
          requires: { provider_name: my_provider }

envoy 自动验 JWT,无效 401。验过的 claim 转发给 backend。
backend 不必再写 JWT 验逻辑。

ext_authz(外部鉴权 service)

复杂鉴权(动态 ACL / per-resource permission)→ envoy 调外部 service:

http_filters:
  - name: envoy.filters.http.ext_authz
    typed_config:
      grpc_service:
        envoy_grpc:
          cluster_name: ext_authz_cluster

每请求 envoy → gRPC 调 authz service → allow/deny。
集中 policy decision,service 不写 authz。

observability

# admin endpoint
admin:
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

http://localhost:9901/stats → 几百个 metric。
http://localhost:9901/clusters → 当前 cluster 状态。

Prometheus scrape /stats/prometheus

tracing

tracing:
  http:
    name: envoy.tracers.opentelemetry
    typed_config:
      grpc_service:
        envoy_grpc:
          cluster_name: otel_collector
      service_name: my-gateway

每请求自动产生 span,发 OTEL collector → Jaeger / Tempo。
backend trace 跟 gateway 串联。

动态配置(xDS)

静态 envoy.yaml 改配置要重启。
xDS API 让 envoy 从 control plane(Istio / Consul / 自家)pull 配置:

dynamic_resources:
  ads_config:
    api_type: GRPC
    grpc_services:
      - envoy_grpc:
          cluster_name: xds_cluster

router / cluster / listener 全运行时改,无中断。
大规模 / 多 envoy 必备。

vs nginx

nginx Envoy
配置 nginx.conf(声明式) yaml + xDS
动态更新 reload(断老连接) xDS 真 hot reload
HTTP/2 / 3 支持但 retrofit first-class
gRPC 透传 原生(gRPC routing)
observability 第三方 内置 metric + trace
学习曲线 高(yaml 长)
资源

简单场景 nginx 够。微服务 + mesh / 动态路由 / gRPC → Envoy。

与 API gateway product 对比

  • Kong:基于 nginx + 插件
  • Tyk:Go 写,open source
  • APISIX:基于 nginx + etcd
  • Envoy + Istio:service mesh 体系

Envoy 是底层 + 通用。Kong/APISIX/Tyk 是产品(envoy 上层封装)。
要 admin UI / 插件市场 → API gateway 产品。
完全自控 → envoy 自配。

真实部署

我们一个 k8s 集群,envoy 当 ingress(替代 nginx-ingress):

  • 200 微服务
  • 10w QPS 峰值
  • envoy 2 replica(HPA 到 8)
  • xDS 控制面 = Istio + 自家 control plane

效果:

  • 配置变更 1 秒 propagate(vs nginx reload 几秒中断)
  • gRPC 路由原生(vs nginx 需要插件)
  • per-service mTLS 自动(mesh 模式)

踩过的坑

  1. yaml 配置长:1000+ 行常见。用 helm / kustomize 模板化。

  2. memory 使用:默认 envoy 几百 MB;大 route 表几 GB。监控 +
    adjust。

  3. JWKS cache miss:JWT auth 频繁拉 JWKS endpoint → IdP rate limit。
    cache_duration: 600s 加大。

  4. route order:从上到下匹配第一个。/ prefix 放最前 → 后面
    都不生效。常见错。

  5. TLS cert reload:file 改了 envoy 不自动 reload。SDS (Secret
    Discovery Service) 动态推或者用 cert-manager + restart envoy
    pod。

精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。