Zuul、Gateway 和 Nginx 有什么区别?

#Java#面试八股

Zuul、Gateway 和 Nginx 有什么区别?

结论先行:三者不是同一层的东西。Nginx 是 C 语言写的反向代理/负载均衡服务器,位于接入层,擅长 TLS 卸载、静态资源与四层转发;Zuul 1 是 Netflix 基于 Servlet 的阻塞式网关,已进入维护模式;Spring Cloud Gateway 基于 WebFlux + Netty 的响应式网关,是 Zuul 1 的官方替代品。

1. 架构与线程模型

Nginx:        master 进程 + N 个 worker 进程(每进程单线程 epoll)
               请求在 worker 内事件驱动,无阻塞

Zuul 1:       Servlet 容器(Tomcat)+ 每请求一线程
               过滤器链在请求线程里同步执行,调下游时线程阻塞

Gateway:      Netty EventLoop + Reactor
               路由、过滤、转发都是异步链路,少量线程扛大量并发

线程模型决定了并发能力:Zuul 1 在慢下游场景下线程会被占满,Gateway 则不会。

2. 能力对比

维度NginxZuul 1Spring Cloud Gateway
语言/生态C,独立于 JVMJava,Spring 生态Java,Spring 生态
线程模型事件驱动多进程Servlet 阻塞Netty 响应式
动态路由改配置 + reload可编程(Filter)可编程(Route/Filter)
服务发现集成需手工/脚本同步可接 Eureka原生 lb://
鉴权/限流需 lua/第三方模块过滤器实现过滤器 + Redis 限流
性能极高(静态/转发)一般高
运维复杂度低(成熟)中中
现状活跃维护模式活跃(官方主推)

3. 配置对照

Nginx:

upstream order_service {
    server 10.0.0.11:8082;
    server 10.0.0.12:8082;
}

server {
    listen 80;
    server_name api.example.com;

    location /api/order/ {
        proxy_pass http://order_service/;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Zuul 1:

zuul:
  routes:
    order-service:
      path: /api/order/**
      serviceId: order-service
      stripPrefix: true

Gateway:

spring:
  cloud:
    gateway:
      routes:
        - id: order_route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=1

后两者的差异在于:Gateway 的断言与过滤器是一等公民,且支持响应式编程;Zuul 1 的过滤器只能同步阻塞地调用下游。

4. Zuul 2 为什么没流行

Zuul 2 改成了 Netty 异步模型,性能大幅提升,但 Netflix 开源节奏放缓、Spring Cloud 官方未集成(Spring Cloud Netflix 只维护 Zuul 1),社区于是转向 Gateway。今天新项目不应再选 Zuul。

5. 实际拓扑:三者共存

客户端
  │ HTTPS
  ▼
Nginx(TLS 卸载、静态资源、限流、WAF)
  │ HTTP
  ▼
Spring Cloud Gateway × N(鉴权、路由、灰度、按服务限流)
  │ lb://
  ▼
业务服务(order / user / stock)

分工原则:Nginx 管「接入」,Gateway 管「业务入口」。把鉴权写在 Nginx 里需要 lua 且难以复用 Spring 的 Bean;把静态资源交给 Gateway 又会浪费 JVM 内存。

6. 常见追问

追问一:Gateway 能替代 Nginx 吗? 不能完全替代。Gateway 是 JVM 应用,处理静态文件和高并发 TLS 不如 Nginx;但业务级路由、鉴权、灰度它更强。生产上二者叠加使用。

追问二:为什么 Zuul 1 在高并发下容易线程耗尽? 它每个请求占用一个 Servlet 线程,调用下游时线程阻塞等待。下游 RT 一高,线程池迅速打满,新请求排队。Gateway 用少量 EventLoop 线程处理海量连接,等待不占线程。

追问三:Nginx 能做服务发现吗? 可以,通过 resolver + 变量 proxy_pass 或 OpenResty + Lua 读注册中心,但实现复杂。K8s 场景下可用 Service/DNS 替代。

追问四:Gateway 的过滤器顺序怎么定? 实现 Ordered 接口,getOrder() 越小越先执行。GlobalFilter 与路由级 GatewayFilter 会被合并排序,NettyRoutingFilter 是最后真正发请求的那个。

追问五:三者性能差距有多大? 单纯转发场景 Nginx 最高(C + epoll),Gateway 次之(Netty),Zuul 1 最低(阻塞 Servlet)。但网关通常不是瓶颈,业务服务的 RT 才是。

小结

选型只需记住层级:接入层用 Nginx,业务网关用 Gateway,Zuul 只存在于历史项目。它们的差别不在「谁更强」,而在「谁该负责哪一段」——把 TLS 和静态资源交给 Nginx,把鉴权与路由交给 Gateway,是最省心的组合。

笔记加载中…