☰
Spring Cloud Gateway 和 Nginx 是重复吗?职责分工与协作实践
2026/10/28 5:15:52 网站建设 项目流程

前阵子团队做技术评审,新来的同事盯着架构图看了一会儿,问了个很经典的问题:“我们已经上了 Spring Cloud Gateway,为什么架构里还要画一个 Nginx?Gateway 不也是网关吗?是不是重复了?”会议室里瞬间分成两派,有人觉得 Gateway 能路由、能过滤、能限流,Nginx 确实多余;有人觉得 Nginx 不能拿掉,但追问到底“不能拿掉”的原因,又说不出个所以然。

这个问题几乎每个 Spring Cloud 团队都会撞上。我自己的结论先说在最前面:Spring Cloud Gateway 和 Nginx 解决的是两个不同层面的问题,生产环境绝大多数场景下它们是“前后配合”的关系,而不是“谁替代谁”的关系。但在特定部署条件下(比如云上已有负载均衡、纯内网服务),Nginx 又确实可以省掉。这篇就把两者的职责边界、协作链路、省或不省的判断标准,以及我在落地时踩过的坑一次讲清楚。

1. 为什么会有这个困惑——两样东西表面看太像了

会反复争论这个问题,根源在于 Gateway 和 Nginx 从“功能清单”上看确实高度重叠。Spring Cloud Gateway 能把/user/**路由到用户服务,Nginx 配置一个location /user/反代到用户服务也能干同样的事;Gateway 能做负载均衡,Nginx 的upstream也能做。再加上很多项目初期是单体架构,最先接触的反向代理工具就是 Nginx,后来微服务化引入了 Spring Cloud Gateway,天然会拿它俩做对比。

但这种对比忽略了一个关键维度:它们所处的流量层级和解决的核心问题完全不同。

我习惯用一个比喻来解释:如果把微服务架构比作一个园区,Nginx 是园区大门口的安保和接待处,负责进门的车辆识别、访客登记、大流量疏导;Spring Cloud Gateway 则是每个楼栋里的前台,负责来访者进了楼之后,该去几层、哪个房间、需不需要刷卡才能进某个区域。大门口的安保不解决楼内怎么走的问题,楼内前台也不该替大门口去拦外面的车流。两者天然是协作关系。

另一个容易混淆的点在于“网关”这个词被用滥了。Spring Cloud Gateway 官方叫 API Gateway,Nginx 在运维语境里也经常被叫“网关”。同一个词,指的不是同一个东西。API Gateway 关注的是 API 层的治理能力,比如协议转换、鉴权、灰度发布、限流熔断;Nginx 关注的是接入层的流量分发和连接管理。两个层级的关注点、性能指标、故障模型完全不一样。

所以纠结“有了 A 还要不要 B”,不如先把各自管什么、各自擅长什么、各自对故障的容忍度是什么搞清楚。这是后面所有判断的基础。

2. Spring Cloud Gateway 的真实职责——应用层的能力边界

Spring Cloud Gateway 是构建在 Spring WebFlux 和 Reactor Netty 之上的响应式网关,核心模型就三个概念:Route(路由)、Predicate(断言)、Filter(过滤器)。路由定义“什么请求到哪里去”,断言定义“什么条件下这条路由生效”,过滤器则负责在请求转发前后做各种处理。这三样组合起来,能实现的东西非常丰富。

2.1 Gateway 最擅长做的事:路由、断言、过滤链

路由不必多说,重点是它和注册中心(Nacos、Eureka、Consul)的联动。Gateway 可以从注册中心动态拉取服务实例列表,服务上下线后路由规则实时生效,不需要重启网关。这一点是 Nginx 做不到的——Nginx 的upstream里的后端地址基本是静态配置,服务地址变了要靠运维手动改配置或者配合脚本 reload。

断言是 Gateway 比较有特色的能力,支持按照时间、Header、Cookie、Host、Method、Path、Query 等条件决定路由是否生效。比如灰度发布场景,我可以写一条断言:Header 里有version=gray的请求路由到灰度服务,其他请求走稳定服务。这种细粒度的条件路由,放在 Nginx 层做会很别扭,但放在 Gateway 层就是一行配置的事。

过滤器链是 Gateway 的核心价值。鉴权、IP 白名单、请求头改写、响应头改写、重试、熔断、限流,全部可以通过 GlobalFilter 或 GatewayFilter 实现。团队里只要有 Java 开发能力,想做什么业务相关的过滤逻辑都很方便,因为过滤器就是写代码,可以调用任何内部服务、查任何配置、做任何复杂的业务判断。这是 Nginx 靠 Lua 脚本或 OpenResty 才能勉强做到的事,而且维护成本不在一个量级。

2.2 Gateway 不太擅长也不该硬扛的事

尽管 Gateway 功能很强,但有几个短板是架构设计时必须正视的。

第一,并发连接处理和极端流量冲击能力远不如 Nginx。Netty 的异步模型本身不差,但 Gateway 进程里跑的是业务过滤器链,一旦某个过滤器有阻塞操作(比如同步调数据库、调 Redis),整个事件循环线程就会被拖住,吞吐量断崖式下跌。而 Nginx 的 worker 进程模型对纯转发场景的并发承受能力极强,单机扛几万并发连接是常有的事。

第二,Gateway 没有边缘接入层的完整能力。TLS 终止可以做,但证书管理、HTTP/2 的优化、WebSocket 的长连接维持、TCP/UDP 的四层转发,这些边缘能力 Gateway 要么支持得不够好,要么根本不是设计目标。非要让 Gateway 全部承担,代码会越来越脏,性能也越来越难看。

第三,从故障面来看,Gateway 一旦挂掉影响的是整个应用层。如果它直接暴露给外部流量,意味着所有恶意扫描、攻击流量、异常请求都会直接打到应用层组件上。应用层网关被迫去处理很多它不该关心的事,比如 SYN Flood、慢速连接攻击、畸形报文,这些恰恰是边缘层工具更擅长防御的。

3. Nginx 在这套架构里的真实位置——不是替代品,是前置守门员

弄清楚 Gateway 的边界之后,Nginx 的位置就自然浮现出来了。在 Spring Cloud 微服务架构里,我更愿意把 Nginx 定义为流量接入层,而不是简单叫它“网关”。它站在整个系统的最前端,和外部网络打交道,Gateway 退到它后面,专心做应用层路由和治理。

3.1 Nginx 的看家本领:连接管理、TLS 终止、静态资源

先说连接管理。Nginx 采用多进程 + 事件驱动的异步非阻塞模型,每个 worker 进程可以处理海量连接,内存占用还很低。面对公网流量那堆乱七八糟的连接请求,让 Nginx 在最外层消化掉大部分无效连接和握手压力,比把这种压力直接释放给 Java 应用层要稳妥得多。

TLS 终止是另一个典型场景。生产环境 HTTPS 证书通常统一在边缘层管理,Nginx 做 TLS 卸载之后,内部链路用 HTTP 明文通信,或者用内部 CA 做轻量级加密。这样证书更新、过期监控、协议版本控制都集中在一个地方,而不是散落在每个微服务里。Spring Cloud Gateway 也能挂证书,但多个服务实例都要配证书、都要管续期,运维复杂度直接翻倍。

静态资源处理方面,前后端分离的项目里,前端打包出来的index.html、JS、CSS、图片这些静态文件,Nginx 处理起来是性能最高的方案之一,还能配合expires做浏览器缓存、配合 gzip/brotli 做压缩。你要是让 Gateway 去托管这些静态资源,等于让一个 Java 进程干 Nginx 最擅长的脏活累活,完全没有必要。

3.2 Nginx 在微服务场景下的额外价值

除了基础能力,Nginx 在微服务架构里还能扮演几个非常实用的角色。

一个是跨网关的全局流量控制。比如整个系统入口的统一 IP 黑白名单、地域封禁、按 IP 维度限流,这些策略放在 Nginx 层做最合适,因为它在所有业务流量之前,粒度最粗但覆盖面最全。Gateway 层也可以做 IP 限流,但如果有人直接绕过 Gateway 的情况出现,全局策略就失效了,而 Nginx 是最外层,没有这个问题。

另一个是健康检查和被动熔断。Nginx 的upstream可以配置max_fails和fail_timeout,后端连续失败达到阈值后自动摘除节点。虽然 Gateway 自己也从注册中心感知服务健康状态,但 Nginx 这一层是独立于注册中心之外的兜底——万一注册中心出现抖动或者误判,Nginx 还能靠自己的探测逻辑把请求送达到真正健康的实例。

再一个是多网关实例的流量分发。Spring Cloud Gateway 要做高可用,通常是多实例部署,前面必须有一个负载均衡器把流量分摊到各个 Gateway 实例上。这个负载均衡器可以是云上的 SLB/ALB,可以是 K8s 的 Service/Ingress,也可以就是一台 Nginx。如果是自建机房,Nginx 做这个负载均衡是最顺手的方案,配一个 upstream 指向多个 Gateway 实例地址就完事。

4. 一次完整请求的分工——Nginx 和 Gateway 是如何协作的

纸上谈兵没意思,直接看一个生产环境的请求流转链路。假设场景是自建机房部署,没有云负载均衡器,前端是 Nginx + Spring Cloud Gateway 多实例 + Nacos 注册中心 + 若干个微服务。

客户端 ↓ HTTPS (443) CDN / DNS 解析 ↓ Nginx (边缘层) ├── TLS 终止 ├── 静态资源处理 (前端 dist) ├── IP 黑白名单 / 基础限流 ├── HTTP 强转 HTTPS、协议版本处理 ├── upstream gateway-cluster { gateway-1:8080, gateway-2:8080, ... } └── 反向代理到 Gateway 集群 ↓ HTTP (内网) Spring Cloud Gateway (应用网关层) ├── Predicate 匹配路由 ├── GlobalFilter 鉴权 / 灰度策略 / 请求头处理 ├── 限流组件 (如 RequestRateLimiter / Sentinel) ├── 从 Nacos 动态获取服务实例 └── 转发到具体微服务实例 ↓ HTTP (内网) 业务微服务 (user-service, order-service, ...) ├── MySQL / Redis / MQ └── 响应按原链路返回

在这个链路里,Nginx 和 Gateway 各干各的,双方都不会越界。客户端先经过 CDN 和 DNS,到 Nginx 时 HTTPS 握手终止,证书校验、TLS 版本协商都是 Nginx 处理完的。Nginx 判断如果是静态资源请求,直接本地返回;如果是 API 请求,按 upstream 策略转发给某个 Gateway 实例。Gateway 拿到请求后,先走过滤器链做鉴权、限流、灰度匹配,然后根据路由断言找到目标服务,通过负载均衡组件选一个具体实例转发过去。

这里有个小细节容易被忽略:Nginx 到 Gateway 的转发热门用 HTTP/1.1 并设置proxy_http_version 1.1,同时把Host头、X-Forwarded-For、X-Real-IP这些头信息正确传给下一层。如果proxy_set_header Host $host丢了,Gateway 里有些基于 Host 的断言会直接失效,排查起来会让人怀疑人生。

4.1 两层都该配置什么——职责边界表

我把生产环境常见的配置项按层拆开,整理成一张表,团队内部新人来了我一般直接丢这张表给他们:

配置/能力Nginx 层Gateway 层说明
TLS 证书终止负责一般不配证书集中管理,避免多处维护
静态资源返回负责不负责前端资源走 Nginx 直接吐
IP 黑白名单负责可补充全局封禁放边缘,业务级白名单放网关
基础限流(按 IP/连接数)负责不负责挡掉恶意流量,保护应用层
业务鉴权(JWT/OAuth)不负责负责需要调用业务服务和配置,放应用层
路由转发到微服务不负责负责Gateway 从注册中心选实例
灰度路由不负责负责按 Header/Cookie 等条件路由
超时重试可配基础值负责业务级重试两层超时要协调,避免 502/504
访问日志负责连接层日志负责业务审计日志两层日志字段和目的不一样

这张表不是绝对标准,比如你非要在 Nginx 层做 JWT 验证,用 OpenResty 也能做,但维护成本很高。我的原则是:谁能以最低成本、最高可靠性完成这个能力,就放在哪一层。边缘能力往前放,业务能力往后放,不要为了炫技把业务逻辑堆进 Nginx。

4.2 两层之间的超时和重试如何协调

这块是协作里最容易出问题的地方,也是我踩坑最多的地方。Nginx 转发到 Gateway,Gateway 转发到微服务,每一层都有独立的connect timeout、read timeout、send timeout,如果各层配的阈值不协调,会出现一个很诡异的现象:微服务一个耗时 8 秒的接口,明明能正常返回,客户端却收到 502 或 504。

举个真实案例。之前线上一个报表接口,数据量大了之后偶尔会跑 10 秒以上。Nginx 的proxy_read_timeout默认 60 秒,本不该出问题,但 Gateway 的HttpClient全局默认超时我没改,配了 5 秒。结果就是 Gateway 自己等待后端响应超过 5 秒直接断开,Nginx 收到上游异常连接,给客户端返回 502 Bad Gateway。排查的时候看 Nginx 日志全是upstream prematurely closed connection,一度怀疑是 Nginx 的问题,后来抓包才发现是 Gateway 那层的 HttpClient 超时太短。

我的建议是:从客户端到边缘层、从边缘层到网关、从网关到业务服务,超时时间应该逐层递减或保持一致,且下游的超时不能小于上游认为正常的阈值。更稳妥的做法是慢接口尽量异步化,不要在同步链路上硬扛长耗时,否则总有一层会超时断开。

5. 什么场景下真的可以不上 Nginx——判断标准不是“有没有”而是“缺不缺”

虽然前面说了半天 Nginx 的重要性,但也别形成条件反射觉得每个 Spring Cloud 项目都必须上 Nginx。在某些架构条件下,Nginx 确实可以省掉,而且是合理的。

5.1 云上已有负载均衡器和网关产品

如果你用的是公有云,架构大概率是:客户端流量先到云负载均衡(SLB/ALB),再由它转发到 Gateway 集群。云负载均衡本身已经提供了四层/七层的流量分发、健康检查、TLS 终止、DDoS 基础防护等能力,这些恰恰是自建 Nginx 想解决的问题。在这种情况下,再塞一台 Nginx 属于重复建设,纯属给自己增加维护成本。

但是注意一个细节:很多云负载均衡默认只做四层转发(TCP),不做七层(HTTP),TLS 终止还得自己处理,或者选择使用 ALB/HTTP 类型的负载均衡器。选型时看清楚类型,不要默认“云上就不需要任何边缘配置了”。

5.2 纯内网、不直接暴露公网的系统

很多内部系统,比如运维平台、公司内部的管理后台,部署在公司内网,访问链路本身就是可信网络,前面没有任何公网流量压力。这种场景,请求直接打到 Gateway,由 Gateway 做鉴权后路由到后端服务,完全可行,Nginx 那层边缘防护没有发挥空间,确实可以省掉。我做过几个类似的内部系统,架构图里只有 Gateway + 微服务,跑得很干净。

5.3 K8s 环境下的特殊处理

在 Kubernetes 里部署 Spring Cloud 微服务时,很多人会问:K8s 的 Ingress 是不是可以替代 Nginx?这里要区分一下概念。如果你的集群用的是 ingress-nginx,它本质上是把一个 Nginx 控制器跑在集群里,还是 Nginx 那套东西,只不过形态变成了 K8s 资源对象来管理。如果你的集群用其他 Ingress Controller(比如 Traefik、APISIX),那它们承担的就是接入层职责,相当于你用 Ingress 替代了传统运维体系里的 Nginx。所以不是 Nginx 不用了,而是它的位置被一个形态不同的“边缘层组件”接替了。

还有一种常见做法是:K8s 内部 Service 直接暴露给集群内部流量,完全不需要 Ingress,因为每个微服务的 Service 本身就是一层负载均衡。这种模式下,Gateway 部署为一组 Pod,前面挂一个 Service 提供稳定的集群内访问入口,也没有专门的 Nginx/Ingress 存在。这种架构在自己团队内部调试、测试环境是够用的,但一旦涉及外部流量的正式环境,我一般还是会建议加一层 Ingress 或独立的边缘组件。

6. 实战选型清单——判断你该不该保留 Nginx

把前面几章的内容压缩成一张选型判断清单,你可以拿自己团队的架构逐条对照。

6.1 九条判断标准

场景建议理由
有外部公网流量直接访问系统保留 Nginx 或云负载均衡器边缘层必须存在,保护应用层
全部流量来自内部可信网络可以考虑去掉 Nginx缺少公网压力,边缘防护价值不大
云上已有 ALB/HTTP 负载均衡可以不单独部署 Nginx云产品已覆盖边缘能力
自建机房且无硬件负载均衡强烈建议保留 Nginx它是成本最低的接入层方案
TLS 证书需要集中管理保留 Nginx(或等价边缘组件)避免证书散落在各服务
Gateway 采用多实例部署必须有一个前置负载均衡器Nginx/SLB/Ingress 至少选一个
服务间全走注册中心发现,网关处理业务路由Gateway 承担路由,Nginx 不必做业务路由分工避免配置爆炸
项目是前后端分离,前端资源需要托管保留 Nginx静态资源交给 Nginx 最高效
安全合规要求记录访问来源、全局 IP 封禁保留 Nginx全局策略在边缘层落地

6.2 我的取舍经验:宁可保留,不可缺失

从我这些年经手的项目看,真正能明确去掉 Nginx 的,只有两种情况:一是纯内部系统,流量环境简单可控;二是云上已经有成熟的七层负载均衡产品。其他情况下,哪怕你在 K8s 里用 Ingress 替代,边缘层这个角色也必须有组件承担,而不是直接把流量怼到 Spring Cloud Gateway 上。

有人觉得多一层就多一次网络跳跃,延迟会增加。这个担心理论上成立,但实际上 Nginx 转发到网关的额外延迟通常在毫秒甚至亚毫秒级别,相对整体业务耗时几乎可以忽略。相比那一点点延迟,边缘层带来的安全隔离、连接管理、故障兜底价值要大得多。不要为了省一跳而丢掉整个架构的防护层。

7. 从 502 Bad Gateway 高发现象看两层的配合姿势——排障经验复盘

标题里的热词里有一堆“502 bad gateway”相关的内容,这不是巧合。很多团队在上了 Gateway + Nginx 之后,线上隔三差五出 502,而且两边日志都看了,还经常互相甩锅。这里我把我实际排查过的几个 502 场景和定位思路完整复盘一下,希望对你有用。

7.1 Nginx 日志里的502 Bad Gateway表示什么

先明确一个基本语义:Nginx 返回 502,意味着 Nginx 作为反向代理,无法从上游服务器(这里的上游是 Gateway)获得有效响应。也就是说,问题可能出在Nginx 到 Gateway 这一段链路,也可能出在Gateway 本身没有正常响应。它不一定代表 Gateway 后面的微服务出问题。

排查第一步永远是看 Nginx 的 error.log,关键字是upstream prematurely closed connection、connect() failed、no live upstreams。这几条分别对应不同的原因:

  • connect() failed (111: Connection refused):Gateway 端口没监听,或者 Gateway 挂了。
  • upstream prematurely closed connection while reading response header from upstream:Gateway 接收请求后,还没返回响应头就断开了连接。常见原因是 Gateway 内部超时、请求在过滤器链中抛异常、OOM 被杀。
  • no live upstreams while connecting to upstream:Nginx 配置里所有后端节点都处于不可用状态,被主动摘除了。

7.2 我踩过的典型坑一:Gateway 响应太慢触发 Nginx 超时

这个前面提到过。有个接口平时 200ms,但偶尔遇到大数据量查询会跑到 3 秒以上。Nginx 的proxy_read_timeout当时配成了 2 秒,于是每当慢请求出现,Nginx 就报upstream timed out,客户端收到 502。这个坑其实很好避,但只要 Nginx 配置没和业务方对齐,就会反复出现。

我的建议是:Nginx 层的超时给到一个“业务可容忍的最大耗时”再乘一个系数,比如业务方承诺所有接口 3 秒内返回,那proxy_read_timeout至少配 10 秒,留出足够的容错空间。千万不要卡着业务耗时的线去配超时,那是自己给自己挖坑。

7.3 我踩过的典型坑二:Gateway 线程/连接池耗尽导致连接被掐断

另一种常见的 502 是 Nginx 日志显示upstream prematurely closed connection,但超时时间明明够。这种情况要去看 Gateway 端的日志和监控。我遇到过一次,Gateway 的下游 HttpClient 连接池默认最大连接数偏小,某一个瞬间大量并发请求打进来,连接池被占满,新请求排队等待连接,等待时间超过了某些超时阈值,于是 Gateway 主动断开,Nginx 就报 502。

这个问题的解法分为两层:一是把 Gateway 的 HttpClient 连接池适当调大,二是排查为什么会有瞬间高并发——是否存在热点请求、缓存未命中、上游服务慢导致 Gateway 线程被长时间占用。只看 Nginx 日志是定位不到这一层的,必须联合 Gateway 的日志和指标一起看。

7.4 502 排查的标准动作清单

如果你也遇到 Nginx + Gateway 环境下的 502,建议按这个顺序排查:

  1. 确认 Nginx 错误日志的类型:是connect failed、timed out还是prematurely closed,三种类型方向完全不同。
  2. 确认 Gateway 进程是否存活:直接curl一下 Gateway 的健康检查端点,排除最基础的“机器挂了”问题。
  3. 看 Gateway 侧日志:有没有超时异常、连接池异常、OOM 记录。Spring Cloud Gateway 里可以开启访问日志和指标,用于这类定位。
  4. 检查网络链路:Nginx 和 Gateway 之间是否有防火墙、安全组,是否出现端口被临时限流。
  5. 对比时间线:把 Nginx error.log 的时间和 Gateway 应用日志的时间对齐,找出断开的根因。

上面这套流程帮我在多个项目里快速定位过问题。很多时候 502 不是配置错了,而是各层组件之间的超时、连接数、负载能力不匹配,需要站在整个链路的视角看待,而不是只看某一层的日志。

8. 个人实践里的一点体会:别在这件事上搞“非此即彼”

回到最初的问题:Spring Cloud 体系里有 Gateway,还需要 Nginx 吗?我的答案是:多数场景需要,少数场景可以不需要,但无论如何做架构设计时都要清楚每个组件存在的理由和边界。Gateway 和 Nginx 不是竞争关系,而是上下游关系。Nginx 在边缘扛流量、管连接、做第一道防护;Gateway 在应用层做路由、鉴权、限流和业务治理。两者各司其职,配合得当,整个系统才会既稳又灵活。

如果你现在正处在这个选型的分岔路口,我的建议很简单:先想清楚你的流量从哪里来、要穿透哪几层、各层组件的故障影响面有多大。只要想清楚这几个问题,技术上要不要 Nginx、用什么形态的 Nginx,答案自己会冒出来。别被“有了 A 就不需要 B”这种速成经验带偏,架构设计的核心永远是认清每个组件的位置,而不是简单做减法。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询