🚪 微服务网关:Zuul、Gateway、Kong三国杀

120 阅读9分钟

面试官:微服务网关有什么作用?
候选人:路由转发...
面试官:Zuul和Gateway有什么区别?为什么Gateway性能更好?
候选人:😰💦(这...)

别慌!今天我们深入剖析微服务网关的原理和实战!


🎬 第一章:为什么需要网关?

没有网关的问题

客户端直接调用微服务:

手机App → 订单服务 (http://order.com:8001)
       → 商品服务 (http://product.com:8002)
       → 用户服务 (http://user.com:8003)

问题:
1. 客户端需要记住所有服务地址 ❌
2. 跨域问题(CORS)❌
3. 认证授权分散在各个服务 ❌
4. 限流、熔断难以统一管理 ❌
5. 协议不统一(HTTP、gRPC、WebSocket)❌

有网关的好处

客户端只需要知道网关地址:

手机App → 网关 (http://api.gateway.com)
           ↓
       ┌───┴───┬───────┬───────┐
       ↓       ↓       ↓       ↓
    订单服务 商品服务 用户服务 支付服务

好处:
1. 统一入口 ✅
2. 统一认证授权 ✅
3. 统一限流熔断 ✅
4. 协议转换 ✅
5. 负载均衡 ✅

🎭 生活比喻:酒店前台

没有前台(没有网关):
客人直接去找:
- 客房服务:3楼
- 餐饮服务:2楼
- 会议室:5楼
→ 客人要记住所有位置 ❌

有前台(有网关):
客人只需要找前台:
"我要订房" → 前台帮你转接客房服务
"我要订餐" → 前台帮你转接餐饮服务
→ 前台统一管理,客人省心 ✅

前台的工作(网关的功能):
1. 身份验证(查看客人证件)
2. 路由转发(告诉客人去哪里)
3. 限流控制(房间满了不让住)
4. 安全检查(不让坏人进来)

🌸 第二章:Zuul 1.x - Netflix的第一代网关

架构原理

基于Servlet的阻塞式IO:

┌──────────────────────────────────────┐
│           Zuul 1.x                    │
│                                       │
│  ┌─────────────────────────────┐    │
│  │   Servlet容器(Tomcat)      │    │
│  │                              │    │
│  │   每个请求一个线程           │    │
│  │   └─ 线程1 处理请求1         │    │
│  │   └─ 线程2 处理请求2         │    │
│  │   └─ 线程3 处理请求3         │    │
│  └─────────────────────────────┘    │
│                                       │
│  Filter链:                          │
│  PRE → ROUTING → POST → ERROR       │
└──────────────────────────────────────┘

问题:
每个请求占用一个线程 → 高并发时线程数暴涨 → 性能瓶颈

核心概念:Filter

// 四种Filter类型
1. PRE Filter:路由前执行(认证、限流)
2. ROUTING Filter:路由时执行(转发请求)
3. POST Filter:路由后执行(添加响应头、日志)
4. ERROR Filter:出错时执行(异常处理)

执行顺序:
请求 → PRE → ROUTING → 后端服务 → POST → 响应
              ↓ 出错            ↓ 出错
            ERROR ←──────────── ERROR

💻 代码示例

// pom.xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

// application.yml
zuul:
  routes:
    order-service:  # 路由名称
      path: /order/**  # 匹配路径
      serviceId: order-service  # 目标服务
    product-service:
      path: /product/**
      serviceId: product-service
  # 敏感头信息(不转发)
  sensitive-headers: Cookie,Set-Cookie
  # 超时配置
  host:
    connect-timeout-millis: 5000
    socket-timeout-millis: 60000

// 启动类
@SpringBootApplication
@EnableZuulProxy  // 启用Zuul
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

// 自定义Pre Filter:Token验证
@Component
public class TokenFilter extends ZuulFilter {
    
    @Override
    public String filterType() {
        return "pre";  // PRE类型
    }
    
    @Override
    public int filterOrder() {
        return 1;  // 执行顺序
    }
    
    @Override
    public boolean shouldFilter() {
        return true;  // 是否执行
    }
    
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        
        // 获取Token
        String token = request.getHeader("Authorization");
        
        if (StringUtils.isEmpty(token)) {
            // 拦截请求
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.setResponseBody("{\"error\":\"未授权\"}");
            return null;
        }
        
        // 验证Token
        if (!validateToken(token)) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(403);
            ctx.setResponseBody("{\"error\":\"Token无效\"}");
            return null;
        }
        
        // 放行
        return null;
    }
    
    private boolean validateToken(String token) {
        // 实际项目中:JWT验证、Redis查询等
        return "valid-token".equals(token);
    }
}

// 自定义Post Filter:响应日志
@Component
public class ResponseLogFilter extends ZuulFilter {
    
    @Override
    public String filterType() {
        return "post";
    }
    
    @Override
    public int filterOrder() {
        return 100;
    }
    
    @Override
    public boolean shouldFilter() {
        return true;
    }
    
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        
        long startTime = (Long) ctx.get("startTime");
        long duration = System.currentTimeMillis() - startTime;
        
        log.info("请求路径: {}, 耗时: {}ms", 
            request.getRequestURI(), duration);
        
        return null;
    }
}

⚖️ 优缺点

✅ 优点

  1. 简单易用:基于Servlet,熟悉
  2. Spring Cloud集成:无缝集成
  3. 过滤器扩展:灵活

❌ 缺点

  1. 性能差:阻塞式IO,一请求一线程
  2. 已停更:Netflix已放弃维护
  3. 不支持异步:无法处理长连接

🚀 第三章:Spring Cloud Gateway - 新一代网关

架构原理

基于WebFlux的响应式编程:

┌──────────────────────────────────────┐
│      Spring Cloud Gateway             │
│                                       │
│  ┌─────────────────────────────┐    │
│  │   Netty(非阻塞IO)          │    │
│  │                              │    │
│  │   少量线程处理大量请求       │    │
│  │   线程1 → 请求1,2,3,4...     │    │
│  │   线程2 → 请求5,6,7,8...     │    │
│  └─────────────────────────────┘    │
│                                       │
│  核心概念:                          │
│  Route(路由)                       │
│  Predicate(断言)                   │
│  Filter(过滤器)                    │
└──────────────────────────────────────┘

优点:
异步非阻塞 → 高并发 → 性能优秀 ✅

核心概念

1. Route(路由):
   - ID:唯一标识
   - URI:目标地址
   - Predicate:匹配条件
   - Filter:过滤器链

2. Predicate(断言):
   - Path:路径匹配
   - Method:方法匹配
   - Header:请求头匹配
   - Query:查询参数匹配
   - After/Before/Between:时间匹配

3. Filter(过滤器):
   - GatewayFilter:单个路由的过滤器
   - GlobalFilter:全局过滤器

💻 代码示例

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

// application.yml
spring:
  cloud:
    gateway:
      routes:
        # 订单服务路由
        - id: order-service
          uri: lb://order-service  # lb表示从注册中心负载均衡
          predicates:
            - Path=/order/**  # 路径断言
            - Method=GET,POST  # 方法断言
          filters:
            - StripPrefix=1  # 去掉路径前缀
            - AddRequestHeader=X-Request-Source, Gateway  # 添加请求头
            
        # 商品服务路由
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/product/**
            - Header=Authorization, Bearer.*  # 必须有Authorization头
          filters:
            - name: RequestRateLimiter  # 限流
              args:
                redis-rate-limiter.replenishRate: 10  # 每秒10个令牌
                redis-rate-limiter.burstCapacity: 20  # 桶容量20
                
      # 全局配置
      default-filters:
        - AddResponseHeader=X-Response-Source, Gateway
      
      # 全局跨域配置
      globalcors:
        cors-configurations:
          '[/**]':
            allowed-origins: "*"
            allowed-methods: "*"
            allowed-headers: "*"

// 启动类
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

// 方式2:Java代码配置路由
@Configuration
public class GatewayConfig {
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("order-service", r -> r
                .path("/order/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .addRequestHeader("X-Request-Source", "Gateway")
                    .retry(config -> config
                        .setRetries(3)  // 重试3次
                        .setStatuses(HttpStatus.INTERNAL_SERVER_ERROR)
                    )
                )
                .uri("lb://order-service")
            )
            .build();
    }
}

// 自定义全局过滤器:Token验证
@Component
@Order(-1)  // 优先级:数字越小越先执行
public class AuthFilter implements GlobalFilter {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 白名单:登录接口不需要Token
        String path = request.getURI().getPath();
        if (path.startsWith("/login")) {
            return chain.filter(exchange);
        }
        
        // 获取Token
        String token = request.getHeaders().getFirst("Authorization");
        
        if (StringUtils.isEmpty(token)) {
            // 返回401
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        
        // 验证Token(实际项目中:JWT验证)
        if (!validateToken(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            return exchange.getResponse().setComplete();
        }
        
        // 放行
        return chain.filter(exchange);
    }
    
    private boolean validateToken(String token) {
        // JWT验证逻辑
        return true;
    }
}

// 自定义过滤器:请求日志
@Component
public class LogFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        long startTime = System.currentTimeMillis();
        
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            long duration = System.currentTimeMillis() - startTime;
            String path = exchange.getRequest().getURI().getPath();
            int statusCode = exchange.getResponse().getStatusCode().value();
            
            log.info("请求路径: {}, 状态码: {}, 耗时: {}ms", 
                path, statusCode, duration);
        }));
    }
    
    @Override
    public int getOrder() {
        return 100;  // 执行顺序
    }
}

// 自定义限流器KeyResolver
@Bean
public KeyResolver ipKeyResolver() {
    // 基于IP限流
    return exchange -> Mono.just(
        exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
    );
}

@Bean
public KeyResolver userKeyResolver() {
    // 基于用户ID限流
    return exchange -> Mono.just(
        exchange.getRequest().getHeaders().getFirst("userId")
    );
}

高级特性

1️⃣ 熔断降级

// application.yml
spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/order/**
          filters:
            - name: CircuitBreaker
              args:
                name: orderCircuitBreaker
                fallbackUri: forward:/fallback/order  # 降级地址

// 降级处理
@RestController
public class FallbackController {
    
    @RequestMapping("/fallback/order")
    public Mono<Map<String, Object>> orderFallback() {
        return Mono.just(Map.of(
            "code", 500,
            "message", "订单服务暂时不可用,请稍后再试"
        ));
    }
}

2️⃣ 动态路由

@Service
public class DynamicRouteService {
    
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    /**
     * 动态添加路由
     */
    public void addRoute(RouteDefinition definition) {
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        // 发布刷新事件
        eventPublisher.publishEvent(new RefreshRoutesEvent(this));
    }
    
    /**
     * 动态删除路由
     */
    public void deleteRoute(String routeId) {
        routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();
        eventPublisher.publishEvent(new RefreshRoutesEvent(this));
    }
}

⚖️ 优缺点

✅ 优点

  1. 性能优秀:异步非阻塞,Netty
  2. Spring生态:无缝集成Spring Cloud
  3. 功能强大:限流、熔断、重试
  4. 持续更新:官方维护

❌ 缺点

  1. 学习曲线:响应式编程较难
  2. 调试困难:异步代码不好调试

🦁 第四章:Kong - 云原生API网关

架构原理

基于OpenResty(Nginx + Lua):

┌────────────────────────────────────────┐
│              Kong Gateway               │
│                                         │
│  ┌──────────────────────────────────┐  │
│  │   OpenResty (Nginx + Lua)        │  │
│  └──────────────────────────────────┘  │
│                                         │
│  ┌──────────────────────────────────┐  │
│  │   Plugin System                  │  │
│  │   - 认证插件                     │  │
│  │   - 限流插件                     │  │
│  │   - 日志插件                     │  │
│  │   - ...                          │  │
│  └──────────────────────────────────┘  │
│                                         │
│  数据库:PostgreSQL / Cassandra         │
└────────────────────────────────────────┘

优点:
Nginx的高性能 + Lua的灵活性

核心概念

1. Service:上游服务
2. Route:路由规则
3. Consumer:消费者(调用方)
4. Plugin:插件(功能扩展)
5. Upstream:负载均衡配置

💻 配置示例

# 1. 创建Service
curl -i -X POST http://localhost:8001/services \
  --data name=order-service \
  --data url=http://order.service.com:8080

# 2. 创建Route
curl -i -X POST http://localhost:8001/services/order-service/routes \
  --data paths[]=/order \
  --data methods[]=GET \
  --data methods[]=POST

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

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

# 5. 创建Consumer
curl -i -X POST http://localhost:8001/consumers \
  --data username=user1

# 6. 为Consumer创建JWT凭证
curl -i -X POST http://localhost:8001/consumers/user1/jwt

常用插件

认证类:
- JWT:JWT认证
- OAuth2.0:OAuth2.0认证
- Key Auth:API Key认证
- Basic Auth:基础认证

安全类:
- IP Restriction:IP白名单/黑名单
- CORS:跨域配置
- Bot Detection:机器人检测

流量控制:
- Rate Limiting:限流
- Request Size Limiting:请求大小限制
- Response Rate Limiting:响应限流

日志类:
- File Log:文件日志
- HTTP Log:HTTP日志
- TCP Log:TCP日志

⚖️ 优缺点

✅ 优点

  1. 性能最强:Nginx+Lua,C语言级性能
  2. 插件丰富:官方+社区,100+插件
  3. 多语言:不依赖特定语言
  4. 云原生:K8s原生支持

❌ 缺点

  1. 学习成本高:需要懂Nginx、Lua
  2. 依赖数据库:PostgreSQL/Cassandra
  3. 调试困难:Lua代码不好调试
  4. 商业版收费:高级功能需付费

📊 第五章:性能对比

压测数据

测试环境:
- 机器:4核8G
- 后端服务:简单的Hello World

压测结果(QPS):

Kong:     15000 QPS  ⭐⭐⭐⭐⭐
Gateway:  10000 QPS  ⭐⭐⭐⭐
Zuul 1.x: 2000 QPS   ⭐⭐

结论:Kong > Gateway >> Zuul

功能对比

功能Zuul 1.xGatewayKong
性能⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
限流需自己实现✅内置✅插件
熔断需Hystrix✅内置✅插件
认证需自己实现需自己实现✅插件
协议HTTPHTTP/WebSocketHTTP/gRPC/WebSocket
语言JavaJava任意
学习曲线简单中等复杂
维护状态已停更活跃活跃

选型建议

Zuul 1.x:不推荐(已停更)

Gateway:
✅ Spring Cloud生态
✅ 中小规模(QPS < 1万)
✅ 团队熟悉Java

Kong:
✅ 超高性能需求(QPS > 1万)
✅ 多语言环境
✅ K8s云原生
✅ 有运维能力

🎓 第六章:面试高分回答

问题:Zuul和Gateway有什么区别?

标准回答

"Zuul和Gateway都是微服务网关,但底层实现完全不同:

Zuul 1.x

  • 基于Servlet的阻塞式IO
  • 一个请求占用一个线程,直到响应
  • 性能:约2000 QPS
  • 已停止更新
  • 适合:老项目维护

Spring Cloud Gateway

  • 基于WebFlux的响应式编程
  • 底层是Netty,异步非阻塞
  • 少量线程处理大量请求
  • 性能:约10000 QPS(5倍于Zuul)
  • Spring官方维护
  • 适合:新项目首选

我们项目的选择: 从Zuul迁移到了Gateway,原因:

  1. 性能提升5倍
  2. 支持WebSocket长连接
  3. 内置限流、熔断功能
  4. Spring Cloud官方支持"

常见追问

Q:Gateway为什么性能更好?

A:
1. IO模型:
   - Zuul:BIO(阻塞IO),一请求一线程
   - Gateway:NIO(非阻塞IO),事件驱动

2. 线程模型:
   - Zuul:请求线程 = 业务线程,高并发时线程暴涨
   - Gateway:IO线程(少量)+ 业务线程(EventLoop)

3. 底层框架:
   - Zuul:Servlet容器(Tomcat)
   - Gateway:Netty(高性能网络框架)

🎁 总结

一句话记住

  • Zuul:老款汽车,已停产 🚗
  • Gateway:新能源车,官方推荐 🚙
  • Kong:超级跑车,专业级 🏎️

祝你面试顺利!💪✨