API Gateway 设计模式:Kong、Envoy、Spring Cloud Gateway 与 KrakenD 对比

API Gateway 架构全景:传统网关 vs 边车网关 vs 服务网格网关,Kong/Envoy/SCG/KrakenD 10维对比,限流熔断灰度发布生产配置。

目录

  1. API Gateway 的核心定位
  2. 三大架构模式:Edge、Sidecar 与 Service Mesh Ingress
  3. Kong:OpenResty + Lua 插件生态
  4. Envoy:C++ 性能怪兽与 WASM 扩展
  5. Spring Cloud Gateway:Java 生态的贴身后卫
  6. KrakenD:超高速聚合网关
  7. 十维对比:选型一张表搞定
  8. 高级模式:聚合、BFF 与熔断
  9. 安全加固:OAuth2、API Key 与 WAF
  10. 性能调优实战
  11. Kubernetes 生产部署:Ingress + Helm
  12. FAQ
  13. 总结与选型建议

1. API Gateway 的核心定位

在微服务架构中,API Gateway 是流量的唯一入口,承担着以下职责:

  • 路由转发:将外部请求按路径、Host、Header 路由到后端服务。
  • 协议转换:HTTP/1.1 与 HTTP/2、gRPC、WebSocket 之间的协议桥接。
  • 横切关注点:认证、鉴权、限流、熔断、日志、监控。
  • 聚合与裁剪:将多个下游 API 聚合成一个端点,减少客户端连接数。
  • 灰度与蓝绿:基于权重、Header、Cookie 实现流量切换。

API Gateway 不是简单的反向代理(如 Nginx),而是具有业务语义的智能路由层。它的设计直接影响系统的可用性、安全性和演进能力。


2. 三大架构模式:Edge、Sidecar 与 Service Mesh Ingress

2.1 Edge Gateway(边缘网关)

Edge Gateway 部署在集群边界,所有外部流量先经过它再进入内部服务。这是最经典的模式,代表产品包括 Kong、Nginx、AWS API Gateway、阿里云 API 网关。

架构特征

  • 单点入口,集中管理证书和防火墙规则。
  • 客户端无感知后端拆分,网关内部完成路由。
  • 适合南北向流量(North-South Traffic)。

优点

  • 运维简单,TLS 证书、WAF、DDoS 防护集中在边缘。
  • 客户端只需记住一个域名。

缺点

  • 集中式意味着单点瓶颈,需要水平扩展和会话保持策略。
  • 跨集群通信时,Edge Gateway 之间需要额外的联邦机制。
# 边缘网关架构示意(伪配置)
edge_gateway:
  listeners:
    - port: 443
      tls: true
      certificates:
        - cert: /etc/ssl/certs/api.example.com.crt
          key: /etc/ssl/private/api.example.com.key
  routes:
    - match:
        path: /api/v1/users
      backend:
        service: user-service
        port: 8080
    - match:
        path: /api/v1/orders
      backend:
        service: order-service
        port: 8080

2.2 Sidecar Gateway(边车网关)

Sidecar Gateway 将网关能力下沉到每个服务实例旁边,通常与 Service Mesh(如 Istio、Linkerd)结合。Envoy 是最典型的 Sidecar 代理。

架构特征

  • 每个 Pod 或容器附带一个 Envoy Sidecar。
  • 进出流量被 iptables 拦截,透明地经过 Sidecar。
  • 适合东西向流量(East-West Traffic)的精细化治理。

优点

  • 去中心化,无单点故障。
  • 可实现服务级别的细粒度熔断、重试、超时。

缺点

  • 资源开销增加,每个 Pod 多一个容器。
  • 调试链路变长,需要掌握 Sidecar 日志和指标。
# Kubernetes Sidecar 注入示意
# Istio 通过 mutating webhook 自动注入 Envoy
apiVersion: v1
kind: Pod
metadata:
  name: user-service-pod
  annotations:
    sidecar.istio.io/inject: "true"
spec:
  containers:
    - name: user-service
      image: user-service:1.2.3
      ports:
        - containerPort: 8080
    # 以下容器由 Istio 自动注入
    - name: istio-proxy
      image: istio/proxyv2:1.20.0
      args:
        - proxy
        - sidecar

2.3 Service Mesh Ingress(服务网格入口网关)

Service Mesh Ingress 是 Edge Gateway 与 Sidecar 的混合体。Istio Gateway、Consul Ingress Gateway 属于此类。它们在网格边缘部署专用的 Envoy 实例,既具备 Edge Gateway 的入口能力,又享有 Service Mesh 的统一控制面。

架构特征

  • 入口流量先进入 Istio Gateway(Envoy),再分发到网格内的 Sidecar。
  • 控制面(istiod)统一通过 xDS 协议推送路由规则。
  • 支持 mTLS 全链路加密,无需应用改造。

优点

  • 统一的流量管理界面,南北向与东西向规则一致。
  • 强大的可观测性(Envoy 原生生成 Prometheus、Jaeger 数据)。

缺点

  • 学习曲线陡峭,控制面故障会影响全集群。
  • 小型团队可能过度设计。
# Istio Gateway + VirtualService 示例
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: public-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 443
        name: https
        protocol: HTTPS
      tls:
        mode: SIMPLE
        credentialName: api-tls-secret
      hosts:
        - "api.example.com"
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: user-route
spec:
  hosts:
    - "api.example.com"
  gateways:
    - public-gateway
  http:
    - match:
        - uri:
            prefix: /api/v1/users
      route:
        - destination:
            host: user-service
            port:
              number: 8080

3. Kong:OpenResty + Lua 插件生态

3.1 架构概述

Kong 基于 OpenResty(Nginx + LuaJIT)构建,通过 Lua 插件扩展功能。其架构分为:

  • 数据平面(DP):OpenResty 进程处理请求,加载路由和插件配置。
  • 控制平面(CP):PostgreSQL 或 Cassandra 存储配置,Admin API 供外部管理。

Kong 3.x 引入了混合模式(Hybrid Mode):CP 和 DP 分离,DP 通过 gRPC 从 CP 同步配置,适合大规模集群。

3.2 核心组件关系

Client
  -> Nginx Listener (OpenResty)
    -> Lua Access Phase
      -> Plugin Iterator (认证、限流、转换)
        -> Lua Balancer Phase
          -> Upstream Service

3.3 Declarative 配置示例(DB-less 模式)

Kong 支持无数据库模式,通过 kong.yml 声明式配置,适合容器化和 GitOps。

# kong.yml — Kong 声明式配置(DB-less 模式)
_format_version: "3.0"

# 定义上游服务
services:
  - name: user-service
    url: http://user-service:8080
    # 路由匹配规则
    routes:
      - name: user-api-route
        paths:
          - /api/v1/users
        methods:
          - GET
          - POST
        strip_path: false
        preserve_host: false

  - name: order-service
    url: http://order-service:8080
    routes:
      - name: order-api-route
        paths:
          - /api/v1/orders
        methods:
          - GET

# 全局插件配置
plugins:
  # 速率限制:每分钟 100 次请求
  - name: rate-limiting
    config:
      minute: 100
      policy: local
      fault_tolerant: true
      hide_client_headers: false
    # 作用范围:全局

  # JWT 认证
  - name: jwt
    service: user-service
    config:
      uri_param_names: []
      cookie_names: []
      key_claim_name: iss
      secret_is_base64: false
      claims_to_verify:
        - exp

  # 跨域支持
  - name: cors
    config:
      origins:
        - "https://app.example.com"
      methods:
        - GET
        - POST
        - PUT
        - DELETE
      headers:
        - Authorization
        - Content-Type
      max_age: 3600
      credentials: true

# 消费者与凭证(模拟)
consumers:
  - username: mobile-app
    jwt_secrets:
      - algorithm: HS256
        key: mobile-app-key
        secret: super-secret-key-do-not-share-in-production

3.4 自定义 Lua 插件示例

当内置插件无法满足需求时,可以编写自定义 Lua 插件。

-- plugins/custom-header-handler.lua
-- 自定义插件:为响应添加追踪头

local CustomHeaderHandler = {
  VERSION = "1.0.0",
  PRIORITY = 1000, -- 插件执行优先级,数字越大越早执行
}

-- 在 Access 阶段执行
function CustomHeaderHandler:access(conf)
  -- 从请求头中提取追踪 ID,若不存在则生成
  local trace_id = kong.request.get_header("X-Request-ID")
  if not trace_id or trace_id == "" then
    trace_id = kong.request.get_id() -- 生成唯一 ID
    kong.service.request.set_header("X-Request-ID", trace_id)
  end
  -- 将追踪 ID 存入上下文,供后续阶段使用
  kong.ctx.shared.trace_id = trace_id
end

-- 在 Header Filter 阶段执行
function CustomHeaderHandler:header_filter(conf)
  local trace_id = kong.ctx.shared.trace_id
  if trace_id then
    -- 在响应头中返回追踪 ID,方便客户端排查问题
    kong.response.set_header("X-Trace-ID", trace_id)
  end
  -- 添加安全响应头
  kong.response.set_header("X-Content-Type-Options", "nosniff")
  kong.response.set_header("X-Frame-Options", "DENY")
end

return CustomHeaderHandler

3.5 Kong 的插件执行阶段

阶段用途
certificate动态证书选择(SNI)
rewrite重写 URI、修改请求属性
access认证、鉴权、限流、路由选择
balancer负载均衡算法、健康检查
header_filter修改响应头
body_filter修改响应体(流式)
log异步日志、指标上报

4. Envoy:C++ 性能怪兽与 WASM 扩展

4.1 架构概述

Envoy 是 Lyft 开源的 C++ L7 代理,设计目标是高性能 + 可观测性 + 可扩展性。它是 Istio、AWS App Mesh、Consul Connect 的数据面核心。

核心概念:

  • Listener:监听端口,接收下游连接。
  • Filter Chain:对流量进行过滤处理(如 HTTP 连接管理、gRPC-JSON 转码)。
  • Cluster:上游服务集群,负责负载均衡和健康检查。
  • Route:基于 URL、Header 匹配路由到具体 Cluster。

4.2 静态配置示例

# envoy.yaml — Envoy 静态配置示例
static_resources:
  listeners:
    - name: listener_http
      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
                codec_type: AUTO
                # 路由配置
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: backend
                      domains: ["*"]
                      routes:
                        # 用户服务路由
                        - match:
                            prefix: "/api/v1/users"
                          route:
                            cluster: user_service_cluster
                            timeout: 5s
                            retry_policy:
                              retry_on: "5xx,connect-failure"
                              num_retries: 3
                              per_try_timeout: 2s
                        # 订单服务路由
                        - match:
                            prefix: "/api/v1/orders"
                          route:
                            cluster: order_service_cluster
                            timeout: 10s
                # HTTP 过滤器链
                http_filters:
                  # WASM 过滤器(见下文)
                  - name: envoy.filters.http.wasm
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
                      config:
                        name: custom_auth_filter
                        root_id: custom_auth_root
                        # 运行时配置(配置源见下)
                        configuration:
                          "@type": type.googleapis.com/google.protobuf.StringValue
                          value: '{"auth_header": "Authorization"}'
                        vm_config:
                          vm_id: custom_auth_vm
                          runtime: envoy.wasm.runtime.v8
                          code:
                            remote:
                              http_uri:
                                uri: https://config.example.com/filters/auth.wasm
                                cluster: config_cluster
                                timeout: 10s
                              sha256: abc123...
                  # 限流过滤器(基于本地令牌桶)
                  - 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: 60s
                      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
                  # 终端过滤器:路由器
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  # 上游集群定义
  clusters:
    - name: user_service_cluster
      connect_timeout: 1s
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      # 连接池配置(性能调优关键)
      circuit_breakers:
        thresholds:
          - priority: DEFAULT
            max_connections: 10000
            max_pending_requests: 10000
            max_requests: 10000
            max_retries: 3000
      load_assignment:
        cluster_name: user_service_cluster
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: user-service
                      port_value: 8080
      # 健康检查
      health_checks:
        - timeout: 2s
          interval: 10s
          unhealthy_threshold: 3
          healthy_threshold: 2
          http_health_check:
            path: /health

    - name: order_service_cluster
      connect_timeout: 1s
      type: STRICT_DNS
      lb_policy: LEAST_REQUEST
      load_assignment:
        cluster_name: order_service_cluster
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: order-service
                      port_value: 8080

    # 远程配置拉取集群
    - name: config_cluster
      connect_timeout: 5s
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: config_cluster
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: config.example.com
                      port_value: 443

4.3 WASM 插件开发

Envoy 支持 WebAssembly(WASM)扩展,允许用 Rust、C++、AssemblyScript 编写过滤器,热更新无需重启进程。

// src/lib.rs — Rust 编写的 Envoy WASM 过滤器(基于 proxy-wasm Rust SDK)
// 功能:检查请求头中的 API Key,无效时返回 401

use proxy_wasm::traits::*;
use proxy_wasm::types::*;
use serde_json::Value;

#[no_mangle]
pub fn _start() {
    proxy_wasm::set_log_level(LogLevel::Info);
    proxy_wasm::set_http_context(|_context_id, root_context_id| -> Box<dyn HttpContext> {
        Box::new(ApiKeyAuthFilter {
            root_context_id,
            auth_header: "X-API-Key".to_string(),
        })
    });
}

struct ApiKeyAuthFilter {
    root_context_id: u32,
    auth_header: String,
}

impl Context for ApiKeyAuthFilter {}

impl HttpContext for ApiKeyAuthFilter {
    // 请求头到达时触发
    fn on_http_request_headers(&mut self, _num_headers: usize, _end_of_stream: bool) -> Action {
        // 读取配置(从 Envoy 配置传入)
        if let Some(config_bytes) = self.get_plugin_configuration() {
            if let Ok(config_str) = std::str::from_utf8(&config_bytes) {
                if let Ok(config_json) = serde_json::from_str::<Value>(config_str) {
                    if let Some(header) = config_json.get("auth_header").and_then(|v| v.as_str()) {
                        self.auth_header = header.to_string();
                    }
                }
            }
        }

        // 获取请求头中的 API Key
        let api_key = self.get_http_request_header(&self.auth_header);

        match api_key {
            Some(key) if !key.is_empty() && validate_key(&key) => {
                // 验证通过,放行请求
                Action::Continue
            }
            _ => {
                // 验证失败,返回 401 Unauthorized
                self.send_http_response(
                    401,
                    vec![("WWW-Authenticate", "Bearer")],
                    Some(b"Unauthorized: invalid or missing API key"),
                );
                Action::Pause
            }
        }
    }
}

// 模拟 API Key 验证(生产环境应从 Vault 或 Redis 获取)
fn validate_key(key: &str) -> bool {
    const VALID_KEYS: &[&str] = &["prod-key-2026-alpha", "prod-key-2026-beta"];
    VALID_KEYS.contains(&key)
}

4.4 xDS 动态配置

Envoy 的强大之处在于支持 xDS(Discovery Service)协议动态获取配置:

  • LDS:Listener Discovery Service
  • RDS:Route Discovery Service
  • CDS:Cluster Discovery Service
  • EDS:Endpoint Discovery Service
  • SDS:Secret Discovery Service

Istio 的 istiod 就是 xDS 控制面,Envoy Sidecar 启动后通过 gRPC 流订阅配置变更。


5. Spring Cloud Gateway:Java 生态的贴身后卫

5.1 架构概述

Spring Cloud Gateway(SCG)基于 Spring 5、Project Reactor 和 Netty 构建,采用异步非阻塞架构。它的定位是 Spring Cloud 微服务体系中的网关层,与 Eureka、Consul、Config Server 深度集成。

核心组件:

  • Route:由 ID、目标 URI、Predicate(断言)和 Filter(过滤器)组成。
  • Predicate:匹配条件(如 Path、Header、Cookie、Method)。
  • Filter:对请求或响应进行修改(如添加头、重写路径、限流)。

5.2 Java 配置类示例

// GatewayConfig.java — Spring Cloud Gateway 路由与过滤器配置
package com.example.gateway.config;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
            // 用户服务路由
            .route("user-service", r -> r
                .path("/api/v1/users/**", "/api/v1/auth/**")
                // 基于权重的灰度发布:90% 流量到 v1,10% 到 v2
                .weight("user-service-group", 90)
                .filters(f -> f
                    // 剥离前缀(可选)
                    .stripPrefix(0)
                    // 添加自定义请求头,传递追踪信息
                    .addRequestHeader("X-Gateway-Source", "spring-cloud-gateway")
                    // 重试策略
                    .retry(retryConfig -> retryConfig
                        .setRetries(3)
                        .setStatuses(INTERNAL_SERVER_ERROR, BAD_GATEWAY, SERVICE_UNAVAILABLE)
                    )
                    // 熔断降级
                    .circuitBreaker(circuitBreakerConfig -> circuitBreakerConfig
                        .setName("userServiceCircuitBreaker")
                        .setFallbackUri("forward:/fallback/user")
                    )
                )
                .uri("lb://user-service")
            )
            // 订单服务路由(强制 HTTPS)
            .route("order-service", r -> r
                .path("/api/v1/orders/**")
                .and().method("GET", "POST")
                .filters(f -> f
                    .rewritePath("/api/v1/orders/(?<segment>.*)", "/orders/${segment}")
                    // 请求限流:基于 Redis 的令牌桶
                    .requestRateLimiter(rateLimiterConfig -> rateLimiterConfig
                        .setRateLimiter(redisRateLimiter())
                        .setKeyResolver(apiKeyResolver())
                    )
                )
                .uri("lb://order-service")
            )
            // WebSocket 路由
            .route("notification-ws", r -> r
                .path("/ws/notifications")
                .uri("lb:ws://notification-service")
            )
            .build();
    }

    // Redis 限流器:每秒 100 请求,突发 200
    @Bean
    public RedisRateLimiter redisRateLimiter() {
        // 参数: replenishRate(每秒填充速率),burstCapacity(桶容量),requestedTokens(每次消耗令牌数)
        return new RedisRateLimiter(100, 200, 1);
    }

    // 按 API Key 限流(替代默认的按用户限流)
    @Bean
    public KeyResolver apiKeyResolver() {
        return exchange -> {
            // 从请求头提取 API Key 作为限流维度
            String apiKey = exchange.getRequest().getHeaders().getFirst("X-API-Key");
            if (apiKey == null || apiKey.isEmpty()) {
                apiKey = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
            }
            return reactor.core.publisher.Mono.just(apiKey);
        };
    }
}

5.3 熔断与降级配置

SCG 通过 Resilience4j 或 Spring Cloud Circuit Breaker 实现熔断。

// FallbackController.java — 熔断降级端点
package com.example.gateway.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/fallback")
public class FallbackController {

    @GetMapping("/user")
    public Mono<String> userServiceFallback() {
        // 用户服务不可用时返回降级数据
        return Mono.just("{\"error\": \"user_service_unavailable\", \"message\": \"服务暂时不可用,请稍后重试\"}");
    }

    @GetMapping("/order")
    public Mono<String> orderServiceFallback() {
        return Mono.just("{\"error\": \"order_service_unavailable\", \"message\": \"订单服务繁忙\"}");
    }
}

5.4 application.yml 极简配置

# application.yml — Spring Cloud Gateway 基础配置
server:
  port: 8080

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      # 全局默认过滤器
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
        - AddResponseHeader=X-Response-Gateway, SCG-v3.2
      # 全局跨域配置
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "https://app.example.com"
            allowedMethods:
              - GET
              - POST
              - PUT
              - DELETE
            allowedHeaders: "*"
            allowCredentials: true
            maxAge: 3600
      # 与 Eureka 集成(可选)
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true

    # Redis 限流依赖 Redis 连接
    redis:
      host: redis.example.com
      port: 6379
      password: ${REDIS_PASSWORD}
      lettuce:
        pool:
          max-active: 100
          max-idle: 50

# 熔断器详细配置(Resilience4j)
resilience4j:
  circuitbreaker:
    configs:
      default:
        slidingWindowSize: 100
        permittedNumberOfCallsInHalfOpenState: 10
        slowCallDurationThreshold: 2s
        slowCallRateThreshold: 80
        failureRateThreshold: 50
        waitDurationInOpenState: 30s
        automaticTransitionFromOpenToHalfOpenEnabled: true

6. KrakenD:超高速聚合网关

6.1 架构概述

KrakenD 是用 Go 编写的高性能 API Gateway,核心特点是无状态、声明式、超快速。它的设计哲学是:在网关层聚合多个后端响应,将 N 次客户端请求合并为 1 次,从而大幅降低延迟。

关键特性:

  • 无状态:配置纯静态,不依赖外部数据库,启动即服务。
  • 聚合能力:单个端点并行调用多个后端,合并 JSON 响应。
  • 属性裁剪:只返回客户端需要的字段,减小带宽。
  • 高性能:基于 Go 的 net/http 和 httprouter,P99 延迟极低。

6.2 krakend.json 完整配置

{
  "$schema": "https://www.krakend.io/schema/v3.json",
  "version": 3,
  "name": "KrakenD API Gateway",
  "timeout": "5s",
  "cache_ttl": "3600s",
  "output_encoding": "json",
  "port": 8080,

  "endpoints": [
    {
      "endpoint": "/api/v1/dashboard",
      "method": "GET",
      "output_encoding": "json",
      "concurrent_calls": 3,
      "timeout": "3s",
      "backend": [
        {
          "url_pattern": "/users/{user_id}",
          "host": ["http://user-service:8080"],
          "method": "GET",
          "group": "user",
          "extra_config": {
            "backend/http": {
              "return_error_details": "user_backend"
            }
          },
          "deny": ["password", "internal_notes"]
        },
        {
          "url_pattern": "/orders?user_id={user_id}",
          "host": ["http://order-service:8080"],
          "method": "GET",
          "group": "orders",
          "extra_config": {
            "backend/http": {
              "return_error_details": "order_backend"
            }
          },
          "deny": ["payment_token"]
        },
        {
          "url_pattern": "/notifications?user_id={user_id}",
          "host": ["http://notification-service:8080"],
          "method": "GET",
          "group": "notifications"
        }
      ],
      "extra_config": {
        "proxy": {
          "flatmap_filter": [
            {
              "type": "del",
              "args": ["user.password"]
            }
          ]
        },
        "qos/ratelimit/router": {
          "max_rate": 500,
          "client_capacity": 100,
          "strategy": "ip"
        }
      }
    },
    {
      "endpoint": "/api/v1/products/{product_id}",
      "method": "GET",
      "backend": [
        {
          "url_pattern": "/products/{product_id}",
          "host": ["http://product-service:8080"],
          "method": "GET"
        }
      ],
      "extra_config": {
        "qos/ratelimit/router": {
          "max_rate": 1000,
          "client_capacity": 200
        },
        "modifier/jmespath": {
          "expr": "{id: id, name: name, price: price, category: category.name}"
        }
      }
    }
  ],

  "extra_config": {
    "telemetry/logging": {
      "level": "INFO",
      "prefix": "[KRAKEND]",
      "syslog": false,
      "stdout": true,
      "format": "default"
    },
    "telemetry/metrics": {
      "collection_time": "60s",
      "proxy_disabled": false,
      "router_disabled": false,
      "backend_disabled": false,
      "endpoint_disabled": false,
      "listen_address": "0.0.0.0:8090"
    },
    "security/cors": {
      "allow_origins": ["https://app.example.com"],
      "allow_methods": ["GET", "POST", "PUT", "DELETE"],
      "allow_headers": ["Authorization", "Content-Type", "X-Request-ID"],
      "expose_headers": ["X-Trace-ID", "X-Request-ID"],
      "max_age": "12h",
      "allow_credentials": true
    },
    "security/http": {
      "allowed_hosts": ["api.example.com"],
      "ssl_proxy_headers": {},
      "sts_seconds": 300,
      "frame_deny": true,
      "content_type_nosniff": true,
      "browser_xss_filter": true
    },
    "plugin/http-server": {
      "name": ["custom-auth-plugin"],
      "custom-auth-plugin": {
        "auth_endpoint": "http://auth-service:8080/validate"
      }
    }
  }
}

6.3 聚合响应效果

当客户端请求 GET /api/v1/dashboard?user_id=42 时,KrakenD 并行请求三个后端,返回合并结果:

{
  "user": {
    "id": 42,
    "name": "张三",
    "email": "zhangsan@example.com"
  },
  "orders": [
    { "id": 1001, "total": 299.0, "status": "shipped" },
    { "id": 1002, "total": 59.9, "status": "pending" }
  ],
  "notifications": [
    { "id": 5001, "message": "订单已发货" }
  ]
}

这种聚合模式也称为 Backend for Frontend(BFF) 的网关层实现,避免了前端多次请求。


7. 十维对比:选型一张表搞定

对比维度KongEnvoySpring Cloud GatewayKrakenD
编程语言OpenResty (Lua/C)C++Java (Netty)Go
架构模式Edge / HybridEdge / Sidecar / MeshEdge (Spring Cloud)Edge
配置方式Admin API / DB-less YAML静态 YAML / xDS 动态Java DSL / YAML / 配置中心静态 JSON(无状态)
扩展机制Lua 插件WASM / C++ 过滤器 / LuaJava Filter / GlobalFilterGo 插件 / Lua(企业版)
请求聚合需自定义插件需自定义 WASM / 外部服务自定义 Filter原生支持,并行聚合
限流算法本地计数器 / Redis 集群本地令牌桶 / 全局 gRPCRedis 令牌桶(内置)本地令牌桶 / IP 策略
服务发现DNS / Consul / Eureka / K8s原生支持 EDS / Strict DNSEureka / Consul / K8s(原生)DNS / Consul / etcd
TLS/mTLS动态证书 / ACME动态 SDS / 全链路 mTLSJDK TLS(需配置)TLS(静态证书)
可观测性Prometheus / Datadog / Zipkin原生 Prometheus / Statsd / OpenTelemetrySpring Boot Actuator / MicrometerPrometheus / OpenTelemetry
吞吐量极高(C++ 异步)中高(受 JVM GC 影响)极高(Go 轻量)

关键选型建议

场景推荐方案
需要丰富插件生态、传统运维团队Kong
已用 Istio/Service Mesh、追求极致性能Envoy
纯 Java/Spring Cloud 生态、团队熟悉 JVMSpring Cloud Gateway
高频聚合场景、追求低延迟与简单运维KrakenD

8. 高级模式:聚合、BFF 与熔断

8.1 响应聚合模式

聚合模式减少客户端往返,通常由网关并行调用多个服务并合并结果。以下是在 Envoy 中通过 External Processing(ext_proc) 或自建聚合服务实现的思路。

# 聚合模式:Envoy + 独立的 Aggregation Service
# Envoy 将 /api/v1/dashboard 路由到聚合服务,由聚合服务内部调用下游
static_resources:
  listeners:
    - name: main_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: main
                route_config:
                  virtual_hosts:
                    - name: aggregation
                      domains: ["*"]
                      routes:
                        - match: { prefix: "/api/v1/dashboard" }
                          route:
                            cluster: aggregation_service
                            timeout: 5s
                        - match: { prefix: "/api/v1/" }
                          # 直接透传其他请求
                          route:
                            cluster: catch_all_cluster
                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters:
    - name: aggregation_service
      connect_timeout: 1s
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: aggregation_service
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address: { address: aggregation-service, port_value: 8080 }

8.2 Backend for Frontend(BFF)模式

BFF 为不同客户端(iOS、Android、Web、H5)提供定制化的 API 网关层,各自独立演进。

// bff-mobile/middleware/gateway.js — Node.js BFF 层示例
// BFF 负责调用内部微服务,按移动端需求裁剪和聚合数据

const express = require('express');
const axios = require('axios');
const circuitBreaker = require('opossum');

const router = express.Router();

// 创建带熔断器的 HTTP 客户端
const userServiceRequest = async (userId) => {
  const response = await axios.get(`http://user-service:8080/users/${userId}`, {
    timeout: 2000,
    headers: { 'X-Internal-Source': 'bff-mobile' }
  });
  return response.data;
};

const breaker = new circuitBreaker(userServiceRequest, {
  timeout: 3000,          // 请求超时
  errorThresholdPercentage: 50, // 错误率阈值
  resetTimeout: 30000,    // 打开后等待 30s 进入半开状态
  volumeThreshold: 10     // 最小请求量
});

// 熔断打开时的降级逻辑
breaker.fallback(() => ({
  id: null,
  name: '用户服务暂不可用',
  avatar: '/static/default-avatar.png',
  level: 'normal'
}));

// 聚合端点:移动端首页数据
router.get('/mobile/home', async (req, res) => {
  const userId = req.headers['x-user-id'];
  try {
    // 并行调用多个服务(聚合模式)
    const [userProfile, promotions, unreadCount] = await Promise.all([
      breaker.fire(userId),
      axios.get('http://promo-service:8080/active', { timeout: 1000 }).catch(() => ({ data: [] })),
      axios.get(`http://notification-service:8080/unread/${userId}`, { timeout: 1000 }).catch(() => ({ data: 0 }))
    ]);

    // 按移动端需求裁剪字段(BFF 核心职责)
    res.json({
      user: {
        name: userProfile.name,
        avatar: userProfile.avatar,
        level: userProfile.membership_level
      },
      banners: promotions.data.slice(0, 3), // 只取前 3 个横幅
      unread: unreadCount.data
    });
  } catch (error) {
    res.status(502).json({ error: 'home_data_unavailable', detail: error.message });
  }
});

module.exports = router;

8.3 熔断器模式(Circuit Breaker)

熔断器防止故障级联,有三种状态:Closed(正常)、Open(熔断)、Half-Open(探测)。

// Resilience4jCircuitBreakerConfig.java — 多服务熔断配置
package com.example.gateway.resilience;

import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
public class Resilience4jCircuitBreakerConfig {

    @Bean
    public CircuitBreakerRegistry circuitBreakerRegistry() {
        // 用户服务:低延迟、高敏感
        CircuitBreakerConfig userConfig = CircuitBreakerConfig.custom()
            .failureRateThreshold(50)
            .slowCallRateThreshold(80)
            .slowCallDurationThreshold(Duration.ofMillis(500))
            .permittedNumberOfCallsInHalfOpenState(10)
            .slidingWindowSize(100)
            .waitDurationInOpenState(Duration.ofSeconds(15))
            .recordExceptions(java.io.IOException.class, java.util.concurrent.TimeoutException.class)
            .build();

        // 订单服务:允许较高延迟,容忍度更高
        CircuitBreakerConfig orderConfig = CircuitBreakerConfig.custom()
            .failureRateThreshold(60)
            .slowCallRateThreshold(90)
            .slowCallDurationThreshold(Duration.ofSeconds(2))
            .permittedNumberOfCallsInHalfOpenState(5)
            .slidingWindowSize(50)
            .waitDurationInOpenState(Duration.ofSeconds(30))
            .build();

        return CircuitBreakerRegistry.ofDefaults()
            .circuitBreaker("userServiceCircuitBreaker", userConfig)
            .circuitBreaker("orderServiceCircuitBreaker", orderConfig);
    }
}

9. 安全加固:OAuth2、API Key 与 WAF

9.1 OAuth2 / OIDC 集成(Kong 示例)

# 在 kong.yml 中配置 OAuth2 / OIDC 插件
plugins:
  - name: openid-connect
    service: user-service
    config:
      # 身份提供商(IdP)发现端点
      issuer: https://auth.example.com/realms/production
      client_id:
        - gateway-client
      client_secret:
        - ${OIDC_CLIENT_SECRET}
      # 令牌验证方式:introspection(自省)或 jwk(本地公钥)
      auth_methods:
        - bearer
      bearer_token_param_type:
        - header
      # 令牌自省端点(推荐生产使用,支持撤销检查)
      introspection_endpoint: https://auth.example.com/realms/production/protocol/openid-connect/token/introspect
      introspection_client_id: introspection-client
      introspection_client_secret: ${INTROSPECTION_SECRET}
      # 缓存自省结果,减少 IdP 压力
      introspection_cache_ttl: 300
      # 权限提取
      scopes_required:
        - read:users
        - write:users
      scopes_claim:
        - scope
        - scopes
      # 用户信息转发给上游
      upstream_headers_claims:
        - sub
        - preferred_username
        - email
      upstream_headers_names:
        - X-User-ID
        - X-Username
        - X-User-Email
      redirect_uri:
        - https://api.example.com/callback

9.2 API Key 管理(Envoy WASM + 外部验证)

前文已展示 WASM 校验 API Key 的 Rust 代码。生产环境建议搭配 API Key 管理后台,支持按应用、环境、有效期维度管理密钥,并在网关层通过高速缓存(如 Redis)减少外部验证延迟。

# Envoy 搭配外部授权服务(ExtAuthz)进行 API Key 校验
http_filters:
  - name: envoy.filters.http.ext_authz
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
      grpc_service:
        envoy_grpc:
          cluster_name: ext_authz_cluster
        timeout: 0.5s
      include_peer_certificate: false
      transport_api_version: V3
      # 校验通过后,将外部服务返回的头信息传递给上游
      metadata_context_namespaces:
        - envoy.filters.http.ext_authz

9.3 Web Application Firewall(WAF)

WAF 在网关层拦截 SQL 注入、XSS、恶意爬虫等攻击。

# ModSecurity WAF 集成(常见搭配 Nginx / OpenResty)
# 在 Kong/nginx.conf 中加载 ModSecurity
server {
    listen 443 ssl;
    server_name api.example.com;

    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;

    # 启用 OWASP Core Rule Set(CRS)
    modsecurity_rules '
        SecRuleEngine On
        SecRequestBodyAccess On
        SecResponseBodyAccess On
        SecResponseBodyLimit 524288
        # 自定义规则:拦截特定 User-Agent
        SecRule REQUEST_HEADERS:User-Agent "@contains BadBot" \
            "id:1000,phase:1,deny,status:403,msg:\'Blocked BadBot\'"
    ';

    location / {
        proxy_pass http://upstream_backend;
    }
}

10. 性能调优实战

10.1 连接池调优

连接复用是网关性能的核心。每次新建 TCP 连接的三次握手和 TLS 握手会显著增加延迟。

# Envoy 连接池与 HTTP2 调优
clusters:
  - name: high_perf_upstream
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    # HTTP/2 上游支持(启用多路复用)
    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: {}
    # HTTP 连接池配置
    common_http_protocol_options:
      idle_timeout: 3600s
    upstream_connection_options:
      tcp_keepalive:
        keepalive_probes: 3
        keepalive_time: 300
        keepalive_interval: 75
    # 负载均衡健康检查
    health_checks:
      - timeout: 1s
        interval: 5s
        healthy_threshold: 1
        unhealthy_threshold: 3
        http_health_check:
          path: /health
          expected_statuses:
            start: 200
            end: 200

10.2 响应缓存

# Kong 响应缓存插件配置
plugins:
  - name: proxy-cache
    config:
      response_code:
        - 200
        - 301
        - 404
      request_method:
        - GET
        - HEAD
      content_type:
        - text/plain
        - application/json
      cache_ttl: 300
      strategy: memory
      # 按 Host + URI 生成缓存键
      cache_key_use_host: true
      cache_key_use_uri: true
      # 需要绕过的头
      vary_headers:
        - Accept-Language

10.3 压缩

# Envoy Gzip 压缩过滤器
http_filters:
  - name: envoy.filters.http.compressor
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor
      response_direction_config:
        common_config:
          min_content_length: 100
          content_type:
            - text/plain
            - text/html
            - application/json
            - application/javascript
      compressor_library:
        name: text_optimized
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip
          memory_level: 5
          compression_level: BEST_SPEED
          compression_strategy: DEFAULT_STRATEGY
          window_bits: 12

11. Kubernetes 生产部署:Ingress + Helm

11.1 Kong Ingress Controller(Helm)

# 添加 Kong Helm 仓库
helm repo add kong https://charts.konghq.com
helm repo update

# 生产级安装:PostgreSQL + Ingress Controller + 监控
helm install kong kong/kong \
  --namespace gateway \
  --create-namespace \
  --set ingressController.enabled=true \
  --set ingressController.installCRDs=true \
  --set postgresql.enabled=true \
  --set postgresql.auth.username=kong \
  --set postgresql.auth.password="$(openssl rand -base64 16)" \
  --set proxy.type=LoadBalancer \
  --set proxy.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-type"="nlb" \
  --set proxy.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-cross-zone-load-balancing-enabled"="true" \
  --set resources.requests.cpu=1000m \
  --set resources.requests.memory=2Gi \
  --set resources.limits.cpu=4000m \
  --set resources.limits.memory=4Gi \
  --set autoscaling.enabled=true \
  --set autoscaling.minReplicas=3 \
  --set autoscaling.maxReplicas=20 \
  --set autoscaling.targetCPUUtilizationPercentage=70 \
  --set podDisruptionBudget.enabled=true \
  --set podDisruptionBudget.minAvailable=2 \
  --set metrics.enabled=true \
  --set metrics.serviceMonitor.enabled=true
# 部署后创建 Ingress 规则
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  namespace: default
  annotations:
    konghq.com/strip-path: "false"
    konghq.com/plugins: rate-limit-100, jwt-auth
spec:
  ingressClassName: kong
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /api/v1/users
            pathType: Prefix
            backend:
              service:
                name: user-service
                port:
                  number: 8080
          - path: /api/v1/orders
            pathType: Prefix
            backend:
              service:
                name: order-service
                port:
                  number: 8080

11.2 Istio Gateway + 自动注入

# Istio 生产安装(精简版)
istioctl install --set profile=default \
  --set meshConfig.accessLogFile=/dev/stdout \
  --set meshConfig.enableAutoMtls=true \
  --set values.global.proxy.resources.requests.cpu=100m \
  --set values.global.proxy.resources.requests.memory=128Mi \
  --set values.global.proxy.resources.limits.cpu=2000m \
  --set values.global.proxy.resources.limits.memory=1Gi

# 为命名空间启用自动 Sidecar 注入
kubectl label namespace default istio-injection=enabled --overwrite
# 生产级 Istio Gateway + VirtualService(灰度发布)
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: production-gateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 443
        name: https
        protocol: HTTPS
      tls:
        mode: SIMPLE
        credentialName: api-tls-cert
      hosts:
        - api.example.com
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: user-service-canary
  namespace: default
spec:
  hosts:
    - api.example.com
  gateways:
    - istio-system/production-gateway
  http:
    - match:
        - headers:
            x-canary:
              exact: "true"
      route:
        - destination:
            host: user-service
            subset: v2
          weight: 100
    - route:
        - destination:
            host: user-service
            subset: v1
          weight: 95
        - destination:
            host: user-service
            subset: v2
          weight: 5
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: user-service-versions
  namespace: default
spec:
  host: user-service
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 1000
      http:
        http1MaxPendingRequests: 500
        http2MaxRequests: 1000
    loadBalancer:
      simple: LEAST_CONN
    outlierDetection:
      consecutive5xxErrors: 5
      interval: 30s
      baseEjectionTime: 30s
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2

12. FAQ

Q1:API Gateway 与反向代理(Nginx)的核心区别是什么?

Nginx 作为反向代理主要负责四层/七层转发、负载均衡和静态资源服务。API Gateway 在此基础上增加了业务语义——认证鉴权、协议转换、请求/响应转换、限流熔断、灰度发布、日志追踪等。简言之,Nginx 是基础设施,API Gateway 是应用层组件。

Q2:服务 already 使用了 Sidecar(Envoy),还需要单独的 Edge Gateway 吗?

建议保留。Sidecar 主要处理东西向流量(服务间通信),Edge Gateway 处理南北向流量(外部客户端)。Istio Gateway 本身就是一种 Edge Gateway,它将 Envoy 部署在网格边缘,统一收口外部流量并接入 mTLS。如果没有 Service Mesh,独立的 Kong / KrakenD 作为 Edge Gateway 仍是最佳实践。

Q3:Kong 的 DB-less 模式和高可用模式(Hybrid)如何选择?

  • DB-less 模式:配置通过 kong.yml 声明式管理,适合容器化、GitOps、配置变更不频繁的场景。Kong 节点完全无状态,重启即恢复。
  • Hybrid 模式:CP 使用 PostgreSQL 存储,DP 通过 gRPC 从 CP 同步配置。适合大规模集群(100+ 节点)、需要 Admin API 动态下发配置、多集群联邦治理的场景。

Q4:Spring Cloud Gateway 的性能瓶颈通常在哪里?如何解决?

主要瓶颈有三:

  1. JVM GC:长耗时 GC 导致请求暂停。建议使用 G1 / ZGC,并合理设置堆内存。
  2. 阻塞式 Filter:自定义 Filter 中使用了阻塞 I/O(如 JDBC、同步 HTTP)。应全部替换为 Reactive 流(WebClient / R2DBC)。
  3. 限流 Redis RTT:每次请求都去 Redis 取令牌。可通过本地缓存 + 异步批量同步策略优化,或改用本地限流(牺牲全局一致性)。

Q5:KrakenD 的并发调用如果某个后端失败,如何处理?

KrakenD 默认采用 “尽力聚合” 策略。单个后端失败时,其他后端的结果仍然返回,失败的后端字段包含错误信息(需开启 return_error_details)。如果业务要求全部成功才返回,可以通过 Sequential Proxy 插件实现串行调用,或者在外部聚合服务中自行实现事务补偿逻辑。


13. 总结与选型建议

API Gateway 是微服务架构的咽喉要道,选型需综合考虑团队技术栈、性能需求、运维能力和生态兼容性。

  • Kong 凭借 Lua 插件生态和成熟的社区支持,是大多数传统企业的稳妥选择。DB-less 模式让它在云原生时代依然游刃有余。
  • Envoy 凭借 C++ 原生性能、WASM 扩展能力和 xDS 动态配置,是 Service Mesh 时代的事实标准。若已采用 Istio,Envoy 是无需额外选型的默认答案。
  • Spring Cloud Gateway 与 Java 生态无缝衔接,适合已深度使用 Spring Boot / Spring Cloud 的团队。其异步非阻塞架构在 JVM 生态中表现优异,但需警惕 GC 和阻塞操作的陷阱。
  • KrakenD 以无状态、原生聚合和高吞吐著称,是前端聚合(BFF)和高性能边缘网关的利器。配置极简,运维成本极低。

在生产环境中,分层网关策略往往最有效:

  1. L4 层:云厂商 Load Balancer(如 AWS NLB、阿里云 SLB)负责证书卸载和 DDoS 清洗。
  2. L7 Edge 层:Kong / KrakenD / Istio Gateway 负责路由、认证、限流、灰度。
  3. Service Mesh 层:Envoy Sidecar 负责东西向流量治理、熔断、mTLS。

通过分层,每一层各司其责,既避免了单点过载,又保证了架构的可演进性。最终,网关的选型不是技术崇拜,而是对业务场景和团队能力的精准匹配

继续阅读

探索更多技术文章

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

全部文章 返回首页

「distributed-systems」更多文章

  1. 分布式高可用架构模式:多活、容灾、降级与 K8s 编排高可用
  2. 分布式链路追踪实战:OpenTelemetry、Jaeger 与 W3C Trace Context
  3. 分布式缓存深度策略:Redis Cluster、一致性哈希与多级缓存架构