搜 索

高性能网关技术选型

  • 216阅读
  • 2022年06月06日
  • 0评论
首页 / 编程 / 正文
本文属于《从入门到放弃》系列,但这次你不能放弃,因为选错网关的代价,就是大促当天看着监控屏幕上的曲线一路向下,然后开始思考人生。

前言:一个选错网关的惨痛教训

某电商公司,技术团队意气风发地选择了某款"主流"网关,理由很充分:"大厂都在用"。

上线后一切正常,日常流量稳稳的。

双十一来了,0点刚过,流量瞬间涨了50倍——

网关CPU直接100%,请求开始排队,响应时间从50ms飙到5秒,然后10秒,然后超时。

用户疯狂刷新,流量继续涨,网关彻底躺平。

整个系统在用户最需要的时刻,集体罢工。

事后复盘:网关选型没考虑极端场景,同步阻塞模型扛不住突发流量。

这个故事告诉我们:网关是系统的咽喉,选错了,全身都得窒息。

一、什么是网关?

1.1 网关的定位

网关(Gateway)是系统的统一入口,所有外部请求都要经过它。就像古代城池的城门,所有人进城都得从这儿过。

graph TB subgraph 外部 Client1["📱 移动端"] Client2["💻 Web端"] Client3["🤖 第三方"] end subgraph 网关层 GW["🚪 API Gateway
统一入口"] end subgraph 内部服务 S1["用户服务"] S2["订单服务"] S3["商品服务"] S4["支付服务"] end Client1 --> GW Client2 --> GW Client3 --> GW GW --> S1 GW --> S2 GW --> S3 GW --> S4 style GW fill:#e17055,color:#fff,stroke-width:3px

1.2 网关的核心职责

网关不只是个"路由器",它承担着很多关键职责:

mindmap root((API Gateway)) 路由转发 路径匹配 负载均衡 服务发现 安全防护 认证鉴权 IP黑白名单 防刷限流 流量管控 限流熔断 灰度发布 A/B测试 协议转换 HTTP/HTTPS WebSocket gRPC转HTTP 监控运维 日志采集 链路追踪 指标监控

用人话说,网关就是个全能门卫

  • 🚦 交通警察:指挥请求去哪个服务
  • 🛂 安检员:验证身份、检查权限
  • 🚧 限流阀:防止流量把后端冲垮
  • 📝 记录员:记录谁来过、干了啥
  • 🔄 翻译官:协议转换、数据格式转换

1.3 为什么需要网关?

没有网关的架构:

graph LR subgraph 客户端 C["Client"] end subgraph 问题多多 C --> S1["用户服务:8001
自己做认证"] C --> S2["订单服务:8002
自己做认证"] C --> S3["商品服务:8003
自己做认证"] C --> S4["支付服务:8004
自己做认证"] end style C fill:#ff6b6b,color:#fff

问题:

  • 客户端要知道每个服务的地址(耦合)
  • 每个服务都要自己实现认证、限流(重复)
  • 服务地址变化,客户端要跟着改(维护噩梦)
  • 没有统一的流量管控(安全隐患)

有了网关:

graph LR subgraph 客户端 C["Client"] end subgraph 网关 GW["Gateway
统一认证/限流/路由"] end subgraph 服务集群 S1["用户服务"] S2["订单服务"] S3["商品服务"] S4["支付服务"] end C --> GW GW --> S1 GW --> S2 GW --> S3 GW --> S4 style GW fill:#1dd1a1,color:#fff,stroke-width:2px

一句话总结:网关是微服务架构的标配,没有网关的微服务架构是不完整的。

二、主流网关技术详解

2.1 Nginx —— 老牌王者,稳如泰山

graph TB subgraph Nginx架构 Master["Master进程
管理Worker"] W1["Worker 1"] W2["Worker 2"] W3["Worker 3"] W4["Worker N..."] end Master --> W1 Master --> W2 Master --> W3 Master --> W4 subgraph 特点 F1["事件驱动"] F2["异步非阻塞"] F3["多进程模型"] end style Master fill:#00b894,color:#fff style W1 fill:#00cec9,color:#fff style W2 fill:#00cec9,color:#fff style W3 fill:#00cec9,color:#fff style W4 fill:#00cec9,color:#fff

核心特点

特性说明
语言C语言
模型事件驱动 + 异步非阻塞 + 多进程
性能极高,单机轻松10万+ QPS
内存极低,10K连接仅需2.5MB
生态超级丰富,各种模块
学习曲线配置语法需要学习

基础配置示例

# nginx.conf
http {
    # 上游服务器组(负载均衡)
    upstream user_service {
        least_conn;  # 最少连接数算法
        server 192.168.1.10:8080 weight=3;
        server 192.168.1.11:8080 weight=2;
        server 192.168.1.12:8080 backup;  # 备用
        
        keepalive 32;  # 连接池
    }
    
    upstream order_service {
        ip_hash;  # IP哈希,会话保持
        server 192.168.1.20:8080;
        server 192.168.1.21:8080;
    }
    
    # 限流配置
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
    
    server {
        listen 80;
        server_name api.example.com;
        
        # 全局限流
        limit_req zone=api_limit burst=200 nodelay;
        limit_conn conn_limit 50;
        
        # 路由规则
        location /api/users {
            proxy_pass http://user_service;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            
            # 超时设置
            proxy_connect_timeout 5s;
            proxy_read_timeout 60s;
            proxy_send_timeout 60s;
        }
        
        location /api/orders {
            # 认证检查
            auth_request /auth;
            
            proxy_pass http://order_service;
        }
        
        # 认证服务
        location = /auth {
            internal;
            proxy_pass http://auth_service/verify;
            proxy_pass_request_body off;
            proxy_set_header Content-Length "";
            proxy_set_header X-Original-URI $request_uri;
        }
        
        # 健康检查
        location /health {
            access_log off;
            return 200 "OK";
        }
    }
}

OpenResty —— Nginx的超级加强版

如果觉得Nginx配置不够灵活,可以用OpenResty,它在Nginx基础上集成了Lua:

# 使用Lua实现复杂限流逻辑
location /api {
    access_by_lua_block {
        local limit_req = require "resty.limit.req"
        local lim, err = limit_req.new("my_limit_store", 500, 200)
        
        local key = ngx.var.binary_remote_addr
        local delay, err = lim:incoming(key, true)
        
        if not delay then
            if err == "rejected" then
                ngx.exit(503)
            end
            ngx.log(ngx.ERR, "限流错误: ", err)
            ngx.exit(500)
        end
        
        if delay > 0 then
            ngx.sleep(delay)
        end
    }
    
    proxy_pass http://backend;
}

适用场景

  • ✅ 超高并发场景(10万+ QPS)
  • ✅ 静态资源服务
  • ✅ 反向代理、负载均衡
  • ✅ 对性能有极致要求
  • ❌ 需要复杂业务逻辑(除非用OpenResty)
  • ❌ 需要与Java生态深度集成

2.2 Zuul & Zuul2 —— Netflix的亲儿子

Zuul 1.x —— 同步阻塞,已经过时

graph LR subgraph Zuul 1.x 架构 REQ["请求"] --> SERVLET["Servlet容器
Tomcat"] SERVLET --> THREAD["线程池
每请求一线程"] THREAD --> FILTER["Filter链"] FILTER --> BACKEND["后端服务"] end style THREAD fill:#ff6b6b,color:#fff

Zuul 1.x 的致命问题:一个请求占用一个线程

假设线程池200个线程,后端服务响应时间100ms,理论最大QPS:

200 / 0.1 = 2000 QPS

一旦后端变慢(比如响应时间变成1秒),QPS直接跌到:

200 / 1 = 200 QPS

这就是为什么Zuul 1.x在流量高峰时容易崩。

// Zuul 1.x 典型配置(Spring Cloud)
@EnableZuulProxy
@SpringBootApplication
public class ZuulGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulGatewayApplication.class, args);
    }
}
# application.yml
zuul:
  routes:
    user-service:
      path: /api/users/**
      serviceId: user-service
      stripPrefix: false
    order-service:
      path: /api/orders/**
      serviceId: order-service
      
  # 超时配置
  host:
    connect-timeout-millis: 5000
    socket-timeout-millis: 60000
    
  # 线程池配置
  ribbon-isolation-strategy: thread
  thread-pool:
    use-separate-thread-pools: true
    thread-pool-key-prefix: zuul

# Hystrix配置
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 60000

Zuul 2.x —— 异步非阻塞,但来得太晚

graph LR subgraph Zuul 2.x 架构 REQ["请求"] --> NETTY["Netty
异步非阻塞"] NETTY --> EVENTLOOP["EventLoop
少量线程处理大量连接"] EVENTLOOP --> FILTER["异步Filter链"] FILTER --> BACKEND["后端服务"] end style NETTY fill:#1dd1a1,color:#fff style EVENTLOOP fill:#00b894,color:#fff

Zuul 2.x 主要改进:

特性Zuul 1.xZuul 2.x
IO模型同步阻塞异步非阻塞
底层框架ServletNetty
线程模型每请求一线程EventLoop
性能一般
Spring Cloud支持完善不支持

但是,Zuul 2.x 有个致命问题:Spring Cloud不支持它

Netflix开源Zuul 2.x时,Spring Cloud团队已经决定自己搞Spring Cloud Gateway了。所以Zuul 2.x就像个弃儿,虽然性能不错,但生态支持很差。

结论:Zuul已经是过去式

  • Zuul 1.x:性能差,不推荐
  • Zuul 2.x:没有Spring Cloud支持,不推荐

如果你的项目还在用Zuul 1.x,建议规划迁移。


2.3 Spring Cloud Gateway —— Spring亲儿子

graph TB subgraph Spring Cloud Gateway 架构 CLIENT["Client"] --> HANDLER["HttpHandler"] HANDLER --> MAPPING["RoutePredicateHandlerMapping
路由匹配"] MAPPING --> FILTER["FilteringWebHandler
过滤器链"] subgraph Filter Chain PRE1["Pre Filter 1"] PRE2["Pre Filter 2"] PROXY["代理请求"] POST1["Post Filter 1"] POST2["Post Filter 2"] end FILTER --> PRE1 --> PRE2 --> PROXY --> POST1 --> POST2 PROXY --> BACKEND["后端服务"] end style HANDLER fill:#6c5ce7,color:#fff style MAPPING fill:#a29bfe,color:#fff style PROXY fill:#00b894,color:#fff

核心特点

特性说明
语言Java
底层框架Spring WebFlux + Project Reactor + Netty
IO模型异步非阻塞
性能高(比Zuul 1.x高1.6倍左右)
Spring生态完美集成
学习曲线需要理解响应式编程

基础配置

依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

配置方式一:YAML配置

spring:
  cloud:
    gateway:
      # 全局默认过滤器
      default-filters:
        - AddRequestHeader=X-Gateway-Source, spring-cloud-gateway
        - AddResponseHeader=X-Response-Time, ${responseTime}
        
      routes:
        # 用户服务路由
        - id: user-service
          uri: lb://user-service  # lb:// 表示从注册中心获取
          predicates:
            - Path=/api/users/**
            - Method=GET,POST,PUT,DELETE
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200
                key-resolver: "#{@userKeyResolver}"
            - name: CircuitBreaker
              args:
                name: userServiceCircuitBreaker
                fallbackUri: forward:/fallback/user
                
        # 订单服务路由
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
            - Header=Authorization, Bearer.*
          filters:
            - StripPrefix=1
            - name: Retry
              args:
                retries: 3
                statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
                methods: GET
                backoff:
                  firstBackoff: 100ms
                  maxBackoff: 500ms
                  factor: 2
                  
        # 基于时间的路由(灰度发布)
        - id: new-product-service
          uri: lb://product-service-v2
          predicates:
            - Path=/api/products/**
            - Between=2024-01-01T00:00:00+08:00, 2024-12-31T23:59:59+08:00
            - Weight=group1, 20  # 20%流量
            
        - id: old-product-service
          uri: lb://product-service-v1
          predicates:
            - Path=/api/products/**
            - Weight=group1, 80  # 80%流量

配置方式二:Java代码配置

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            // 用户服务
            .route("user-service", r -> r
                .path("/api/users/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .addRequestHeader("X-User-Source", "gateway")
                    .requestRateLimiter(c -> c
                        .setRateLimiter(redisRateLimiter())
                        .setKeyResolver(userKeyResolver())
                    )
                    .circuitBreaker(c -> c
                        .setName("userCB")
                        .setFallbackUri("forward:/fallback/user")
                    )
                )
                .uri("lb://user-service")
            )
            // 订单服务
            .route("order-service", r -> r
                .path("/api/orders/**")
                .and()
                .header("Authorization", "Bearer.*")
                .filters(f -> f
                    .stripPrefix(1)
                    .retry(config -> config
                        .setRetries(3)
                        .setStatuses(HttpStatus.BAD_GATEWAY, HttpStatus.SERVICE_UNAVAILABLE)
                        .setMethods(HttpMethod.GET)
                    )
                )
                .uri("lb://order-service")
            )
            .build();
    }
    
    @Bean
    public KeyResolver userKeyResolver() {
        // 基于用户ID限流
        return exchange -> Mono.justOrEmpty(
            exchange.getRequest().getHeaders().getFirst("X-User-Id")
        ).defaultIfEmpty("anonymous");
    }
    
    @Bean
    public KeyResolver ipKeyResolver() {
        // 基于IP限流
        return exchange -> Mono.just(
            exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
        );
    }
    
    @Bean
    public RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(100, 200, 1);
    }
}

自定义过滤器

全局过滤器(所有路由生效)

@Component
@Slf4j
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().toString();
        
        // 白名单路径跳过认证
        if (isWhiteListed(path)) {
            return chain.filter(exchange);
        }
        
        // 获取Token
        String token = request.getHeaders().getFirst("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            return unauthorized(exchange, "Missing or invalid token");
        }
        
        // 验证Token
        try {
            String jwt = token.substring(7);
            Claims claims = JwtUtil.parseToken(jwt);
            
            // 将用户信息传递给下游服务
            ServerHttpRequest mutatedRequest = request.mutate()
                .header("X-User-Id", claims.getSubject())
                .header("X-User-Role", claims.get("role", String.class))
                .build();
                
            return chain.filter(exchange.mutate().request(mutatedRequest).build());
            
        } catch (Exception e) {
            log.warn("Token验证失败: {}", e.getMessage());
            return unauthorized(exchange, "Invalid token");
        }
    }
    
    private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        
        String body = String.format("{\"code\":401,\"message\":\"%s\"}", message);
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
        
        return response.writeWith(Mono.just(buffer));
    }
    
    private boolean isWhiteListed(String path) {
        return path.startsWith("/api/auth/") || 
               path.equals("/health") || 
               path.startsWith("/api/public/");
    }
    
    @Override
    public int getOrder() {
        return -100;  // 优先级最高
    }
}

路由过滤器(特定路由生效)

@Component
public class LoggingGatewayFilterFactory 
        extends AbstractGatewayFilterFactory<LoggingGatewayFilterFactory.Config> {

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            long startTime = System.currentTimeMillis();
            String requestId = UUID.randomUUID().toString();
            
            ServerHttpRequest request = exchange.getRequest().mutate()
                .header("X-Request-Id", requestId)
                .build();
            
            return chain.filter(exchange.mutate().request(request).build())
                .then(Mono.fromRunnable(() -> {
                    long duration = System.currentTimeMillis() - startTime;
                    if (config.isEnabled()) {
                        log.info("Request {} {} completed in {}ms, status: {}",
                            request.getMethod(),
                            request.getPath(),
                            duration,
                            exchange.getResponse().getStatusCode()
                        );
                    }
                }));
        };
    }
    
    @Data
    public static class Config {
        private boolean enabled = true;
    }
}

适用场景

  • ✅ Spring Cloud微服务体系
  • ✅ 需要与Spring生态深度集成
  • ✅ Java技术栈团队
  • ✅ 中高并发场景(万级QPS)
  • ❌ 超高并发场景(考虑Kong或Nginx)
  • ❌ 非Java技术栈

2.4 Kong —— 云原生时代的王者

graph TB subgraph Kong架构 CLIENT["Client"] --> KONG["Kong Gateway
(OpenResty/Nginx)"] subgraph Kong组件 PROXY["Proxy
核心代理"] ADMIN["Admin API
管理接口"] PLUGINS["Plugins
插件系统"] end KONG --> PROXY KONG --> ADMIN KONG --> PLUGINS subgraph 数据存储 POSTGRES["PostgreSQL"] CASSANDRA["Cassandra"] DBLESS["DB-less Mode
(声明式配置)"] end ADMIN --> POSTGRES ADMIN --> CASSANDRA ADMIN --> DBLESS PROXY --> UPSTREAM["Upstream Services"] end style KONG fill:#003459,color:#fff,stroke-width:2px style PLUGINS fill:#00a8e8,color:#fff

核心特点

特性说明
底层OpenResty(Nginx + Lua)
性能极高,毫秒级延迟
插件丰富的官方和社区插件
部署支持DB模式和DB-less模式
云原生原生支持Kubernetes
管理REST API + GUI(Konga)

安装部署

Docker Compose部署

version: '3.8'

services:
  kong-database:
    image: postgres:13
    environment:
      POSTGRES_USER: kong
      POSTGRES_DB: kong
      POSTGRES_PASSWORD: kongpass
    volumes:
      - kong-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "kong"]
      interval: 10s
      timeout: 5s
      retries: 5

  kong-migration:
    image: kong:3.4
    command: kong migrations bootstrap
    environment:
      KONG_DATABASE: postgres
      KONG_PG_HOST: kong-database
      KONG_PG_USER: kong
      KONG_PG_PASSWORD: kongpass
    depends_on:
      kong-database:
        condition: service_healthy

  kong:
    image: kong:3.4
    environment:
      KONG_DATABASE: postgres
      KONG_PG_HOST: kong-database
      KONG_PG_USER: kong
      KONG_PG_PASSWORD: kongpass
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_ADMIN_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG: /dev/stderr
      KONG_ADMIN_ERROR_LOG: /dev/stderr
      KONG_ADMIN_LISTEN: 0.0.0.0:8001
      KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl
    ports:
      - "8000:8000"   # Proxy
      - "8443:8443"   # Proxy SSL
      - "8001:8001"   # Admin API
    depends_on:
      kong-migration:
        condition: service_completed_successfully
    healthcheck:
      test: ["CMD", "kong", "health"]
      interval: 10s
      timeout: 5s
      retries: 5

  konga:
    image: pantsel/konga:latest
    environment:
      NODE_ENV: production
    ports:
      - "1337:1337"
    depends_on:
      - kong

volumes:
  kong-data:

Kubernetes部署(Helm)

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

# 安装Kong Ingress Controller
helm install kong kong/kong \
  --namespace kong \
  --create-namespace \
  --set ingressController.enabled=true \
  --set proxy.type=LoadBalancer

配置管理

Admin API方式

# 创建Service
curl -X POST http://localhost:8001/services \
  --data name=user-service \
  --data url=http://user-service:8080

# 创建Route
curl -X POST http://localhost:8001/services/user-service/routes \
  --data name=user-route \
  --data 'paths[]=/api/users' \
  --data 'methods[]=GET' \
  --data 'methods[]=POST'

# 添加限流插件
curl -X POST http://localhost:8001/services/user-service/plugins \
  --data name=rate-limiting \
  --data config.minute=100 \
  --data config.policy=local

# 添加认证插件
curl -X POST http://localhost:8001/services/user-service/plugins \
  --data name=jwt

# 添加日志插件
curl -X POST http://localhost:8001/services/user-service/plugins \
  --data name=file-log \
  --data config.path=/tmp/kong.log

声明式配置(DB-less模式)

# kong.yml
_format_version: "3.0"
_transform: true

services:
  - name: user-service
    url: http://user-service:8080
    routes:
      - name: user-route
        paths:
          - /api/users
        methods:
          - GET
          - POST
          - PUT
          - DELETE
    plugins:
      - name: rate-limiting
        config:
          minute: 100
          policy: redis
          redis_host: redis
          redis_port: 6379
      - name: jwt
        config:
          secret_is_base64: false
      - name: cors
        config:
          origins:
            - "*"
          methods:
            - GET
            - POST
            - PUT
            - DELETE
            - OPTIONS
          headers:
            - Authorization
            - Content-Type
          max_age: 3600

  - name: order-service
    url: http://order-service:8080
    routes:
      - name: order-route
        paths:
          - /api/orders
    plugins:
      - name: rate-limiting
        config:
          minute: 50
      - name: request-transformer
        config:
          add:
            headers:
              - X-Gateway: kong

# 全局插件
plugins:
  - name: prometheus
  - name: correlation-id
    config:
      header_name: X-Request-ID
      generator: uuid

# 上游配置(负载均衡)
upstreams:
  - name: user-service-upstream
    algorithm: round-robin
    healthchecks:
      active:
        healthy:
          interval: 5
          successes: 2
        unhealthy:
          interval: 5
          http_failures: 3
    targets:
      - target: user-service-1:8080
        weight: 100
      - target: user-service-2:8080
        weight: 100

Kong常用插件

graph TB subgraph 认证授权 JWT["jwt"] KEY["key-auth"] OAUTH["oauth2"] BASIC["basic-auth"] LDAP["ldap-auth"] end subgraph 流量控制 RATE["rate-limiting"] SIZE["request-size-limiting"] TERM["request-termination"] end subgraph 转换 REQ_TRANS["request-transformer"] RESP_TRANS["response-transformer"] CORS["cors"] end subgraph 监控日志 PROM["prometheus"] ZIPKIN["zipkin"] FILE_LOG["file-log"] HTTP_LOG["http-log"] end style JWT fill:#e17055,color:#fff style RATE fill:#00b894,color:#fff style PROM fill:#6c5ce7,color:#fff
插件类型插件名称功能说明
认证jwtJWT Token验证
key-authAPI Key认证
oauth2OAuth2.0认证
basic-authHTTP Basic认证
限流rate-limiting请求限流
request-size-limiting请求体大小限制
转换request-transformer请求转换
response-transformer响应转换
cors跨域支持
监控prometheusPrometheus指标
zipkin分布式追踪
datadogDataDog集成
日志file-log文件日志
http-logHTTP日志上报
tcp-logTCP日志

适用场景

  • ✅ 云原生/Kubernetes环境
  • ✅ 多语言微服务(不限于Java)
  • ✅ 需要丰富的插件生态
  • ✅ 高并发、低延迟场景
  • ✅ 需要API全生命周期管理
  • ❌ 简单场景(杀鸡用牛刀)
  • ❌ 预算有限(企业版较贵)

三、网关性能测试

选网关不能光看文档吹得天花乱坠,得实际压一压。

3.1 测试环境

测试机器:4核8G,CentOS 7
网络:内网千兆
后端服务:简单Echo服务(响应时间约1ms)
压测工具:Gatling

3.2 测试场景

class GatewayBenchmarkSimulation extends Simulation {
  
  val httpProtocol = http
    .baseUrl("http://gateway:8000")
    .acceptHeader("application/json")
  
  val scn = scenario("Gateway Benchmark")
    .exec(
      http("API Request")
        .get("/api/echo")
        .check(status.is(200))
    )
  
  setUp(
    scn.inject(
      // 预热
      rampUsers(100).during(10.seconds),
      // 阶梯加压
      incrementUsersPerSec(100)
        .times(10)
        .eachLevelLasting(30.seconds)
        .separatedByRampsLasting(5.seconds)
        .startingFrom(100)
    )
  ).protocols(httpProtocol)
}

3.3 测试结果

xychart-beta title "网关性能对比(QPS)" x-axis ["100并发", "500并发", "1000并发", "2000并发", "5000并发"] y-axis "QPS (requests/sec)" 0 --> 50000 bar [35000, 42000, 45000, 44000, 43000] bar [8000, 12000, 15000, 14000, 12000] bar [12000, 18000, 22000, 21000, 19000] bar [32000, 40000, 43000, 42000, 41000]
网关100并发500并发1000并发2000并发P99延迟
Nginx35,00042,00045,00044,0005ms
Zuul 1.x8,00012,00015,00014,00089ms
Spring Cloud Gateway12,00018,00022,00021,00023ms
Kong32,00040,00043,00042,0006ms

3.4 资源消耗对比

xychart-beta title "内存消耗对比(1000并发时)" x-axis ["Nginx", "Zuul 1.x", "SCG", "Kong"] y-axis "内存 (MB)" 0 --> 2000 bar [50, 1500, 800, 100]
网关CPU占用内存占用说明
Nginx30%50MB资源消耗极低
Zuul 1.x85%1.5GB线程池占用大量资源
Spring Cloud Gateway60%800MB响应式编程资源占用适中
Kong35%100MB基于Nginx,资源消耗低

3.5 测试结论

  1. 性能排名:Nginx ≈ Kong > Spring Cloud Gateway >> Zuul 1.x
  2. 资源效率:Nginx > Kong > Spring Cloud Gateway >> Zuul 1.x
  3. Spring Cloud Gateway 在中高并发下表现良好,适合大多数Java项目
  4. Zuul 1.x 性能明显落后,不建议新项目使用

四、网关选型决策

4.1 决策流程图

flowchart TD START["开始选型"] --> Q1{"技术栈?"} Q1 -->|纯Java/Spring| Q2{"并发量级?"} Q1 -->|多语言/云原生| Q3{"运维能力?"} Q1 -->|追求极致性能| NGINX["Nginx/OpenResty"] Q2 -->|万级以下| SCG["Spring Cloud Gateway"] Q2 -->|万级以上| Q4{"需要Spring集成?"} Q4 -->|是| SCG_CLUSTER["SCG集群 + 前置Nginx"] Q4 -->|否| KONG Q3 -->|强| KONG["Kong"] Q3 -->|一般| Q5{"K8s环境?"} Q5 -->|是| KONG Q5 -->|否| NGINX style SCG fill:#6c5ce7,color:#fff style KONG fill:#003459,color:#fff style NGINX fill:#00b894,color:#fff

4.2 选型对照表

需求场景推荐方案理由
Spring Cloud微服务Spring Cloud Gateway无缝集成,开发友好
超高并发(10万+ QPS)Nginx/Kong异步IO,性能极致
Kubernetes云原生Kong原生K8s支持,声明式配置
多语言微服务Kong/Nginx语言无关
简单代理需求Nginx简单可靠,运维成本低
需要复杂业务逻辑Spring Cloud GatewayJava开发,灵活扩展
API全生命周期管理Kong Enterprise完整的API管理平台
预算有限Nginx/SCG开源免费

4.3 组合方案

很多时候,单一网关难以满足所有需求,可以考虑组合方案:

graph TB subgraph 双层网关架构 CLIENT["外部流量"] --> LB["负载均衡
(云厂商/F5)"] LB --> NGINX["Nginx集群
流量网关"] subgraph 业务网关层 NGINX --> SCG1["Spring Cloud Gateway 1
业务网关"] NGINX --> SCG2["Spring Cloud Gateway 2
业务网关"] NGINX --> SCG3["Spring Cloud Gateway N
业务网关"] end SCG1 --> SERVICES["微服务集群"] SCG2 --> SERVICES SCG3 --> SERVICES end style NGINX fill:#00b894,color:#fff style SCG1 fill:#6c5ce7,color:#fff style SCG2 fill:#6c5ce7,color:#fff style SCG3 fill:#6c5ce7,color:#fff

双层网关架构的职责分工

层级技术选型职责
流量网关Nginx/KongSSL卸载、限流、黑白名单、负载均衡
业务网关Spring Cloud Gateway认证鉴权、路由、协议转换、业务过滤

这种架构的优点:

  • 流量网关承担高并发压力
  • 业务网关专注业务逻辑
  • 故障隔离,互不影响
  • 可以独立扩容

4.4 各方案优缺点总结

graph TB subgraph Nginx N_PRO["✅ 性能极高
✅ 资源消耗低
✅ 稳定可靠
✅ 生态丰富"] N_CON["❌ 配置不够灵活
❌ 动态配置需reload
❌ 复杂逻辑需Lua"] end subgraph Kong K_PRO["✅ 性能高
✅ 插件丰富
✅ 云原生友好
✅ 动态配置"] K_CON["❌ 运维复杂度高
❌ 企业版较贵
❌ 学习成本"] end subgraph "Spring Cloud Gateway" S_PRO["✅ Spring生态集成
✅ Java开发友好
✅ 响应式编程
✅ 开源免费"] S_CON["❌ 性能不如Nginx/Kong
❌ 需理解WebFlux
❌ 只适合Java栈"] end style N_PRO fill:#1dd1a1,color:#fff style N_CON fill:#ff6b6b,color:#fff style K_PRO fill:#1dd1a1,color:#fff style K_CON fill:#ff6b6b,color:#fff style S_PRO fill:#1dd1a1,color:#fff style S_CON fill:#ff6b6b,color:#fff

4.5 我的建议

根据我的实际项目经验,给出以下建议:

小团队/初创公司

  • 直接用 Spring Cloud Gateway
  • 简单、够用、开发友好
  • 后期流量上来再考虑前置Nginx

中型公司/中等流量

  • Nginx + Spring Cloud Gateway 双层架构
  • Nginx做流量网关
  • SCG做业务网关

大型公司/高并发

  • KongNginx/OpenResty
  • 需要专门的网关运维团队
  • 考虑Kong Enterprise获得商业支持

云原生/Kubernetes

  • Kong Ingress Controller
  • Istio Gateway(如果已经在用Istio)

五、迁移指南

5.1 从Zuul 1.x迁移到Spring Cloud Gateway

// Zuul Filter
public class AuthZuulFilter extends ZuulFilter {
    @Override
    public String filterType() { return "pre"; }
    
    @Override
    public int filterOrder() { return 0; }
    
    @Override
    public boolean shouldFilter() { return true; }
    
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String token = request.getHeader("Authorization");
        if (token == null) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
        }
        return null;
    }
}

// 迁移到 Spring Cloud Gateway
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (token == null) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
    
    @Override
    public int getOrder() { return 0; }
}

5.2 迁移检查清单

□ 路由规则迁移
□ 过滤器逻辑迁移
□ 限流配置迁移
□ 熔断配置迁移
□ 认证逻辑迁移
□ 日志格式调整
□ 监控指标对接
□ 灰度发布验证
□ 性能压测对比
□ 回滚方案准备

六、总结

graph LR A["选网关"] --> B{"你的场景"} B -->|Java + Spring| C["Spring Cloud Gateway"] B -->|超高并发| D["Nginx/Kong"] B -->|云原生| E["Kong"] B -->|简单需求| F["Nginx"] C --> G["中规中矩,够用就好"] D --> H["性能怪兽,值得投入"] E --> I["未来趋势,拥抱云原生"] F --> J["简单可靠,永远的神"] style C fill:#6c5ce7,color:#fff style D fill:#00b894,color:#fff style E fill:#003459,color:#fff style F fill:#e17055,color:#fff

网关选型没有银弹,只有最适合的选择

  1. 性能不是唯一指标:运维成本、开发效率、团队技能都要考虑
  2. 不要过度设计:初期用简单方案,后期按需升级
  3. 实际压测:别信文档,自己压一遍才知道
  4. 预留升级空间:架构要能平滑演进

记住那句老话:没有最好的技术,只有最合适的技术。

选对了网关,大促夜里你可以安心睡觉;选错了,那就准备好咖啡和眼药水吧。


参考资料

评论区
暂无评论
avatar