本文属于《从入门到放弃》系列,但这次你不能放弃,因为选错网关的代价,就是大促当天看着监控屏幕上的曲线一路向下,然后开始思考人生。
前言:一个选错网关的惨痛教训
某电商公司,技术团队意气风发地选择了某款"主流"网关,理由很充分:"大厂都在用"。
上线后一切正常,日常流量稳稳的。
双十一来了,0点刚过,流量瞬间涨了50倍——
网关CPU直接100%,请求开始排队,响应时间从50ms飙到5秒,然后10秒,然后超时。
用户疯狂刷新,流量继续涨,网关彻底躺平。
整个系统在用户最需要的时刻,集体罢工。
事后复盘:网关选型没考虑极端场景,同步阻塞模型扛不住突发流量。
这个故事告诉我们:网关是系统的咽喉,选错了,全身都得窒息。
一、什么是网关?
1.1 网关的定位
网关(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 网关的核心职责
网关不只是个"路由器",它承担着很多关键职责:
用人话说,网关就是个全能门卫:
- 🚦 交通警察:指挥请求去哪个服务
- 🛂 安检员:验证身份、检查权限
- 🚧 限流阀:防止流量把后端冲垮
- 📝 记录员:记录谁来过、干了啥
- 🔄 翻译官:协议转换、数据格式转换
1.3 为什么需要网关?
没有网关的架构:
自己做认证"] C --> S2["订单服务:8002
自己做认证"] C --> S3["商品服务:8003
自己做认证"] C --> S4["支付服务:8004
自己做认证"] end style C fill:#ff6b6b,color:#fff
问题:
- 客户端要知道每个服务的地址(耦合)
- 每个服务都要自己实现认证、限流(重复)
- 服务地址变化,客户端要跟着改(维护噩梦)
- 没有统一的流量管控(安全隐患)
有了网关:
统一认证/限流/路由"] 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 —— 老牌王者,稳如泰山
管理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 —— 同步阻塞,已经过时
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: 60000Zuul 2.x —— 异步非阻塞,但来得太晚
异步非阻塞"] 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.x | Zuul 2.x |
|---|---|---|
| IO模型 | 同步阻塞 | 异步非阻塞 |
| 底层框架 | Servlet | Netty |
| 线程模型 | 每请求一线程 | 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亲儿子
路由匹配"] 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 —— 云原生时代的王者
(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: 100Kong常用插件
| 插件类型 | 插件名称 | 功能说明 |
|---|---|---|
| 认证 | jwt | JWT Token验证 |
| key-auth | API Key认证 | |
| oauth2 | OAuth2.0认证 | |
| basic-auth | HTTP Basic认证 | |
| 限流 | rate-limiting | 请求限流 |
| request-size-limiting | 请求体大小限制 | |
| 转换 | request-transformer | 请求转换 |
| response-transformer | 响应转换 | |
| cors | 跨域支持 | |
| 监控 | prometheus | Prometheus指标 |
| zipkin | 分布式追踪 | |
| datadog | DataDog集成 | |
| 日志 | file-log | 文件日志 |
| http-log | HTTP日志上报 | |
| tcp-log | TCP日志 |
适用场景
- ✅ 云原生/Kubernetes环境
- ✅ 多语言微服务(不限于Java)
- ✅ 需要丰富的插件生态
- ✅ 高并发、低延迟场景
- ✅ 需要API全生命周期管理
- ❌ 简单场景(杀鸡用牛刀)
- ❌ 预算有限(企业版较贵)
三、网关性能测试
选网关不能光看文档吹得天花乱坠,得实际压一压。
3.1 测试环境
测试机器:4核8G,CentOS 7
网络:内网千兆
后端服务:简单Echo服务(响应时间约1ms)
压测工具:Gatling3.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 测试结果
| 网关 | 100并发 | 500并发 | 1000并发 | 2000并发 | P99延迟 |
|---|---|---|---|---|---|
| Nginx | 35,000 | 42,000 | 45,000 | 44,000 | 5ms |
| Zuul 1.x | 8,000 | 12,000 | 15,000 | 14,000 | 89ms |
| Spring Cloud Gateway | 12,000 | 18,000 | 22,000 | 21,000 | 23ms |
| Kong | 32,000 | 40,000 | 43,000 | 42,000 | 6ms |
3.4 资源消耗对比
| 网关 | CPU占用 | 内存占用 | 说明 |
|---|---|---|---|
| Nginx | 30% | 50MB | 资源消耗极低 |
| Zuul 1.x | 85% | 1.5GB | 线程池占用大量资源 |
| Spring Cloud Gateway | 60% | 800MB | 响应式编程资源占用适中 |
| Kong | 35% | 100MB | 基于Nginx,资源消耗低 |
3.5 测试结论
- 性能排名:Nginx ≈ Kong > Spring Cloud Gateway >> Zuul 1.x
- 资源效率:Nginx > Kong > Spring Cloud Gateway >> Zuul 1.x
- Spring Cloud Gateway 在中高并发下表现良好,适合大多数Java项目
- Zuul 1.x 性能明显落后,不建议新项目使用
四、网关选型决策
4.1 决策流程图
4.2 选型对照表
| 需求场景 | 推荐方案 | 理由 |
|---|---|---|
| Spring Cloud微服务 | Spring Cloud Gateway | 无缝集成,开发友好 |
| 超高并发(10万+ QPS) | Nginx/Kong | 异步IO,性能极致 |
| Kubernetes云原生 | Kong | 原生K8s支持,声明式配置 |
| 多语言微服务 | Kong/Nginx | 语言无关 |
| 简单代理需求 | Nginx | 简单可靠,运维成本低 |
| 需要复杂业务逻辑 | Spring Cloud Gateway | Java开发,灵活扩展 |
| API全生命周期管理 | Kong Enterprise | 完整的API管理平台 |
| 预算有限 | Nginx/SCG | 开源免费 |
4.3 组合方案
很多时候,单一网关难以满足所有需求,可以考虑组合方案:
(云厂商/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/Kong | SSL卸载、限流、黑白名单、负载均衡 |
| 业务网关 | Spring Cloud Gateway | 认证鉴权、路由、协议转换、业务过滤 |
这种架构的优点:
- 流量网关承担高并发压力
- 业务网关专注业务逻辑
- 故障隔离,互不影响
- 可以独立扩容
4.4 各方案优缺点总结
✅ 资源消耗低
✅ 稳定可靠
✅ 生态丰富"] 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做业务网关
大型公司/高并发:
- Kong 或 Nginx/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 迁移检查清单
□ 路由规则迁移
□ 过滤器逻辑迁移
□ 限流配置迁移
□ 熔断配置迁移
□ 认证逻辑迁移
□ 日志格式调整
□ 监控指标对接
□ 灰度发布验证
□ 性能压测对比
□ 回滚方案准备六、总结
网关选型没有银弹,只有最适合的选择:
- 性能不是唯一指标:运维成本、开发效率、团队技能都要考虑
- 不要过度设计:初期用简单方案,后期按需升级
- 实际压测:别信文档,自己压一遍才知道
- 预留升级空间:架构要能平滑演进
记住那句老话:没有最好的技术,只有最合适的技术。
选对了网关,大促夜里你可以安心睡觉;选错了,那就准备好咖啡和眼药水吧。