跳至主要內容

十万个why:有了 Spring Cloud Gateway,为什么前面还得挡一层 Nginx?

程序员小富大约 3 分钟

大家好,我是小富~

有同学私信了我这个问题,Nginx 能做反向代理,Gateway 也能做,既然功能重叠,为什么还要两层?

这么想其实是因为看问题的视角局限在了功能上,从架构上看,这两者的定位很清晰的,Nginx 是网络流量网关,Spring Cloud Gateway 是业务网关。

它们不仅不是竞争关系,而是上下游的协作关系。

微服务架构的流量链路中,它们处于不同的层级,正常流程应该是:用户 -> Nginx -> Spring Cloud Gateway -> 微服务

看下边这个图就很容易理解了,Nginx 接收公网的流量,Spring Cloud Gateway 是内网业务逻辑路由。

我列几个还需要 Nginx 的原因

1、静态资源访问

我们现在项目基本都是前后端分离的,后端服务返回业务数据,但前端的那些 HTML、CSS、JS、图片,谁来提供?

Nginx 处理静态文件有天然优势,Nginx 不用把文件数据读到用户态内存,直接通过内核态的 sendfile 系统调用,磁盘文件直接转发给网卡,全程无 CPU 拷贝开销,性能吊打 Java 十条街。

Gateway 基于 Netty 处理静态文件,哪怕用了 Netty 的零拷贝,数据也需要经过磁盘 → 内核缓冲区 → Netty 缓冲区 → 网卡这么走一圈,高并发静态请求下,性能远不如 Nginx。

让它去处理静态文件,有点像开法拉利拉砖,不是不能干,性价比极低。流量治理的逻辑处理,路由转发、限流熔断、灰度发布、鉴权过滤、负载均衡…… 这些才是它的长处。

Nginx 还能做动静分离,前端请求来了 Nginx 判断:

匹配 /api/** -> 转发给 Gateway 去处理业务。

匹配 .html/.js/.css/图片 -> Nginx 直接返回静态资源,毫秒级响应,用户体验很好,java 返回这些页面容易转圈。

2、谁来给网关做负载均衡?

Gateway 自己也是一个 Java 服务,线上肯定要做高可用吧,关键服务不能只部一台,它万一挂了业务服务都访问不了了,好歹来 3 台组成一个集群。

那么问题来了,前端的请求,到底发给 IP1、IP2 还是 IP3?

Nginx 负责把流量均衡地分发给这 3 个 Gateway 节点,没有 Nginx,Gateway 集群就没有入口。

3、SSL

域名要配 HTTPS,SSL/TLS 握手涉及到复杂的非对称加密运算,非常消耗 CPU。

如果在 Gateway 层做 SSL 握手,业务线程会因为计算密集型的解密操作而阻塞,导致系统整体吞吐量下降。

要在 Nginx 层统一配置 SSL 证书,Nginx 负责解密,然后通过内网 HTTP 明文转发给 Gateway,这过程叫 SSL 卸载,与业务无直接关系的脏活就让 Nginx 干,Java 专注于写业务逻辑。

4、运维与开发的互不干扰

个人觉得这个最重要,职责划分清楚了

运维管 Nginx 配置,封禁恶意 IP、调整 gzip 压缩比、配置跨域头(CORS)、升级 OpenSSL 补丁,这些变更不需要重启 Java 服务。

开发管 Gateway 代码,修改路由规则、调整鉴权逻辑、修改参数校验规则,这些变更走代码发布的流程。

如果不分层,运维想封个 IP 还得求开发改代码发版,那就有扯不完皮了。

说在最后

多一层网络转发不一定就浪费性能,在内网千兆环境下,Nginx 转发到 Gateway 的耗时几乎可以忽略不计了。

Gateway 和 Nginx 定位不同,就像前端和后端程序员都写代码,谁取代谁呢,定位职责不同而已!!!

上次编辑于: