在技术选型时,选择 Nginx 和 Spring Cloud Gateway(或简称为 Gateway)主要取决于具体应用场景和技术需求。下面是两者的一些关键差异和适用场景。
一、Nginx
概念
Nginx 是一个高性能的 Web 服务器和反向代理服务器,常被用作静态内容的服务器和负载均衡器。它支持HTTP、HTTPS、SMTP、POP3和IMAP协议,适合处理静态资源、SSL终止、HTTP压缩等任务。
Nginx是一个高性能的HTTP和反向代理服务器,同时也可以用作负载均衡器、HTTP缓存和Web服务器。
Nginx 作为 web 服务器
Nginx 可以作为静态页面的 web 服务器,同时还支持 CGI 协议的动态语言,比如 perl、php 等。但是不支持 java。Java 程序只能通过与 tomcat 配合完成。
Nginx 专为性能优化而开发, 性能是其最重要的考量,实现上非常注重效率,能经受高负载的考验,有报告表明能支持高达 50000 个并发连接数。https://lnmp.org/nginx.html
特点
- 高性能:Nginx能够处理大量并发连接,适合高流量网站。
- 反向代理:Nginx可以作为反向代理,将客户端请求转发到后端服务器。
- 负载均衡:支持多种负载均衡算法(如轮询、最少连接、IP哈希等)。
- 静态内容服务:可以高效地服务静态文件(如HTML、CSS、JavaScript和图片)。
- 模块化:具有丰富的模块,可以根据需要扩展功能。
配置文件
java
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
nginx 配置文件有三部分组成,
第一部分:全局块
从配置文件开始到 events 块之间的内容,主要会设置一些影响nginx 服务器整体运行的配置指令,主要包括配 置运行 Nginx 服务器的用户(组)、允许生成的 worker process 数,进程 PID 存放路径、日志存放路径和类型以 及配置文件的引入等。
比如上面第一行配置的
java
worker_processes 1;
这是 Nginx 服务器并发处理服务的关键配置,worker_processes 值越大,可以支持的并发处理量也越多,但是 会受到硬件、软件等设备的制约。
第二部分:events块
比如上面的配置,
java
events {
worker_connections 1024;
}
events 块涉及的指令主要影响 Nginx 服务器与用户的网络连接,常用的设置包括是否开启对多 work process 下的网络连接进行序列化,是否 允许同时接收多个网络连接,选取哪种事件驱动模型来处理连接请求,每个 word process 可以同时支持的最大连接数等。
上述例子就表示每个 work process 支持的最大连接数为 1024。这部分的配置对 Nginx 的性能影响较大,在实际中应该灵活配置。
第三部分:http块
java
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
这算是 Nginx 服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里。
需要注意的是:http 块也可以包括 http全局块、server 块。
(1)http全局块:http全局块配置的指令包括文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。
(2)server 块:这块和虚拟主机有密切关系,虚拟主机从用户角度看,和一台独立的硬件主机是完全一样的,该技术的产生是为了 节省互联网服务器硬件成本。
每个 http 块可以包括多个 server 块,而每个 server 块就相当于一个虚拟主机。而每个 server 块也分为全局 server 块,以及可以同时包含多个 locaton 块。
- **全局 server 块:**最常见的配置是本虚拟机主机的监听配置和本虚拟主机的名称或IP配置。
- location 块 :这块的主要作用是基于 Nginx 服务器接收到的请求字符串(例如 server_name/uri-string),对虚拟主机名称 (也可以是IP 别名)之外的字符串(例如 前面的 /uri-string)进行匹配,对特定的请求进行处理。 地址定向、数据缓 存和应答控制等功能,还有许多第三方模块的配置也在这里进行。
- 一个 server 块可以配置多个 location 块。
原理
nginx 启动后,是由两个进程组成的。master(管理者)和worker(工作者)。
一个nginx 只有一个master。但可以有多个worker。过来的请求由master管理,worker进行争抢式的方式去获取请求。
主进程(master process)的功能
- 对外接口:接收外部的操作(信号)
- 对内转发:根据外部的操作的不同,通过信号管理 Worker
- 监控:监控 worker 进程的运行状态,worker 进程异常终止后,自动重启 worker 进程
- 读取Nginx 配置文件并验证其有效性和正确性
- 建立、绑定和关闭socket连接
- 按照配置生成、管理和结束工作进程 接受外界指令,比如重启、升级及退出服务器等指令
- 不中断服务,实现平滑升级,重启服务并应用新的配置
- 开启日志文件,获取文件描述符
- 不中断服务,实现平滑升级,升级失败进行回滚处理
- 编译和处理perl脚本
工作进程(worker process)的功能
- 所有 Worker 进程都是平等的
- 实际处理:网络请求,由 Worker 进程处理
- Worker进程数量:一般设置为核心数,充分利用CPU资源,同时避免进程数量过多,导致进程竞争 CPU资源
- 增加上下文切换的损耗
- 接受处理客户的请求
- 将请求依次送入各个功能模块进行处理
- I/O调用,获取响应数据
- 与后端服务器通信,接收后端服务器的处理结果
- 缓存数据,访问缓存索引,查询和调用缓存数据
- 发送请求结果,响应客户的请求
- 接收主程序指令,比如重启、升级和退出等
master-workers 的机制的好处
- 首先,对于每个 worker 进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销, 同时在编程以及问题查找时,也会方便很多。
- 可以使用 nginx --s reload 热部署,利用 nginx 进行热部署操作。
- 其次,采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master 进程则很快启动新的 worker 进程。
- 当然,worker 进程的异常退出,肯定是程序有 bug 了,异常退出,会导致当 前 worker 上的所有请求失败,不过不会影响到所有请求,所以降低了风险。
设置多少个 worker?
Nginx 同 redis 类似,都采用了 io 多路复用机制,每个 worker 都是一个独立的进程,但每个进程里只有一个主线程,通过异步非阻塞的方式来处理请求, 即使是千上万个请求也不在话 下。每个 worker 的线程可以把一个 cpu 的性能发挥到极致。所以 worker 数和服务器的 cpu 数相等是最为适宜的。设少了会浪费 cpu,设多了会造成 cpu 频繁切换上下文带来的损耗。
连接数 worker_connection
第一个:发送请求,占用了 woker 的几个连接数?答案:2 或者 4 个。
第二个:nginx 有一个 master,有四个 woker,每个 woker 支持最大的连接数 1024,支持的 最大并发数是多少?
当然,这里说的是最大连接数,
- 对于 HTTP 请 求 本 地 资 源 来 说 , 能 够 支 持 的 最 大 并 发 数 量 是 worker_connections * worker_processes。
- 如果是支持 http1.1 的浏览器每次访问要占两个连接,
- 所以普通的静态访问最大并发数是: worker_connections * worker_processes /2。
- 如果是 HTTP 作为反向代理来说,最大并发数量应该是 worker_connections * worker_processes/4。因为作为反向代理服务器,每个并发会建立与客户端的连接和与后端服 务的连接,会占用两个连接。
Nginx 进程间通信
工作进程是由主进程生成的,主进程使用fork()函数,在Nginx服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程。
主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单向通道,包含了主进程向工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。
主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件。
当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
worker进程之间的通信原理基本上和主进程与worker进程之间的通信是一样的,只要worker进程之间能够取得彼此的信息,建立管道即可通信,但是由于worker进程之间是完全隔离的,因此一个进程想要知道另外一 个进程的状态信息,就只能通过主进程来实现。
为了实现worker进程之间的交互,master进程在生成worker进程之后,在worker进程表中进行遍历,将该新进程的PID以及针对该进程建立的管道句柄传递给worker进程中的其他进程,为worker进程之间的通信做准备,当worker进程1向worker进程2发送指令的时候,首先在master进程给它的其他worker进程工作信息中找到2的进程PID,然后将正确的指令写入指向进程2的管道,worker进程2捕获到管道中的事件后,解析指令并进行相关操作,这样就完成了worker进程之间的通信。
worker进程可以通过共享内存来通讯的,比如upstream中的zone,或者limit_req、limit_conn中的 zone等。操作系统提供了共享内存机制。
二、Gateway
概念
Spring Cloud Gateway 是Spring Cloud生态中的API网关,专为微服务架构设计。它提供了动态路由、过滤器机制以及集成Spring Cloud DiscoveryClient的服务发现能力,便于实现复杂的API管理需求。
1)Route(路由):路由是构建网关的基本模块,由ID,目标URI,一系列的断言和过滤器组成,如果断言为true,则匹配该路由。
2)Predicate(断言):参考java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(例如请求头、请求参数),如果请求与断言相匹配则进行路由。
3)Filter(过滤):指的是由Spring框架中GatewayFilter实例,使用过滤器,可以在请求被路由之前或者之后对请求进行修改。
过滤器 Filter 按照请求和响应可以分为两种:Pre 类型和 Post 类型。
- Pre 类型:在请求被转发到微服务之前,对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等操作。
- Post 类型:微服务处理完请求后,返回响应给网关,网关可以再次进行处理,例如修改响应内容或响应头、日志输出、流量监控等。
另外一种分类是按照过滤器 Filter 作用的范围进行划分:
- GlobalFilter:全局过滤器,应用在所有路由上的过滤器。
- GatewayFilter:局部过滤器,应用在单个路由或一组路由上的过滤器。标红色表示比较常用的过滤器。
功能
Gateway网关是是所有微服务的统一入口, 网关的核心功能特性主要体现在请求路由,权限控制,限流三部分。
- 路由:由于网关不能处理业务,所以网关需要根据某种规则(断言)把请求转发给匹配的主机或者接口上,这个转发的过程就叫做路由。
- 负载均衡:当路由的目标微服务有多个实例时,还需要通过负载均衡规则从多个服务实例中挑选一个。
- 身份认证(鉴权):网关作为微服务的入口需要校验用户是否有请求资格或是否有权限进行操作,如果没有则拦截。
- 访问控制:设置黑白名单,比如限制DDOS攻击的IP地址。
- 请求限流:当请求量过高时,网关会按照微服务能够接受的速度来放行请求,避免服务压力过大
- 发布控制:比如上线一个新接口时,先给新接口分配 20%流量,老接口分配80%,后续再慢慢调整比例。
- 流量染色:区分用户来源,给请求添加一些标识,一般通过添加新的请求头,全局染色。
- 统一处理跨域:网关统一处理跨域,不用在每个项目单独处理。
- 统一业务处理:把每个项目中都要做的通用逻辑放到上层网关统一处理。
- 统一文档knife4j:将下游项目的文档进行聚合在一个页面统一查看建议用。
- 统一日志: 统一的请求,响应信息记录。
- 接口保护:限制请求,信息脱敏,降级熔断进行兜底,请求限流(令牌桶算法,漏桶算法,RedisLimitHandler),设置超时时间,超时就中断。
。
特点
- 请求路由:根据请求的URL、HTTP方法等,将请求路由到相应的微服务。
- 安全性:可以实现身份验证、授权、速率限制等安全措施。
- 监控和分析:提供API的使用情况统计、流量监控等功能。
- 协议转换:支持不同协议之间的转换,如将HTTP请求转换为WebSocket、gRPC等。
- 聚合请求:可以将多个微服务的请求聚合为一个请求,简化客户端的调用。
GeteWay 处理后请求在微服务中的进一步处理是什么?
Gateway 处理后的请求在微服务中的进一步处理,取决于微服务的具体实现。一般来说,微服务会继续处理这些请求,并根据请求的具体内容和业务逻辑来进行相应的处理。
具体来说,在 Gateway 中,可以通过定义**路由规则(Route)**将请求路由到不同的微服务中。当请求到达微服务后,微服务会根据路由规则中定义的目标地址和路径,将请求转发到相应的服务实例中。在服务实例中,请求会经过一系列的处理过程,包括身份验证、请求过滤、业务处理、数据存储等,最终返回一个响应结果。
例如,假设有一个微服务系统,其中包含了两个服务实例,分别是用户服务和订单服务。当用户在 Gateway 中发起一个请求时,请求会被路由到用户服务中,并经过身份验证、请求过滤等处理后,再根据具体的业务逻辑来进行处理。如果用户需要查询订单信息,则用户服务会将请求路由到订单服务中,并根据订单服务返回的结果来生成相应的响应结果。最终,响应结果会被返回到 Gateway 中,并由 Gateway 负责将其返回给用户。
需要注意的是,微服务架构中的服务实例是可以动态变化的,因此 Gateway 处理后的请求可能需要经过服务注册和发现等过程,才能找到相应的服务实例进行处理。在实际实现中,可以使用服务注册中心、负载均衡等机制来管理服务实例的动态变化,并确保请求能够被正确路由到相应的服务实例中进行处理。
GateWay需要注册到Nacos中吗?如何注册的?
需要,Gateway 需要注册到 Nacos 中,这样才能够实现服务发现和路由转发等功能。
为了达到网关接收到的请求能够负载均衡的转发给每个微服务的实例,我们将微服务网关注册到"服务注册中心",比如nacos。这样就可以gateway接收到请求后,首先从服务注册中心获取到各个微服务实例的访问地址,然后gateway根据客户端负载均衡的规则,选择众多实例中的一个作为请求转发对象。简单的说就是将gateway作为一个"服务调用者"注册到nacos服务注册中心,实现客户端负载均衡。
下面介绍一下如何将 Gateway 注册到 Nacos 中。
(1)在 pom.xml 中引入 Nacos 的依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
(2)在 application.yml 文件中添加 Nacos 的配置
spring:
application:
name: gateway
cloud:
nacos:
server-addr: 192.168.101.65:8848
discovery:
namespace: dev
group: test-project
config:
namespace: dev
group: test-project
file-extension: yaml
refresh-enabled: true
shared-configs:
- data-id: logging-${spring.profiles.active}.yaml
group: test-common
refresh: true
gateway:
discovery:
locator:
enabled: true
lowerCaseServiceId: true
profiles:
active: dev
以上配置中,server-addr
指定 Nacos 的服务地址,namespace
指定网关的命名空间,用于隔离不同环境中的配置。
(3)在 Gateway 的启动类上添加 @EnableDiscoveryClient
注解
java
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
(4)在 Gateway 的配置文件中添加路由规则
Gateway 的路由规则是通过 YAML 配置文件定义的,例如:
java
spring:
cloud:
gateway:
routes:
- id: service-provider # 路由 ID
uri: lb://service-provider # 目标服务地址,使用 Ribbon 进行负载均衡
predicates:
- Path=/hello # 匹配的请求路径
在这个例子中,我们定义了一个路由规则,将 /hello 请求 path 通过服务名 service-provider 路由到目标服务的 /hello 路径上。
至此,我们就可以将 Gateway 注册到 Nacos 中了。当启动 Gateway 应用时,它会自动注册到 Nacos 服务注册中心,以供服务发现和路由转发等功能使用,在nacos控制台可以看到已经注册成功。
工作流程(核心:路由转发+执行过滤链)
Gateway 的工作流程如上图所示:
-
客户端请求:客户端(如Web应用、移动应用等)向API Gateway发送HTTP请求,通常包含请求路径、HTTP方法(GET、POST等)、请求头和请求体。
-
路由判断:客户端的请求到达网关后,先经过 Gateway Handler Mapping 处理,,这里面会做断言(Predicate)判断,看下符合哪个路由规则,这个路由映射后端的某个服务。
- API Gateway根据请求的URL、HTTP方法和其他信息,决定将请求路由到哪个具体的微服务。路由规则可以基于路径、查询参数、请求头等进行定义。
-
请求过滤:然后请求到达 Gateway Web Handler,这里面有很多过滤器,组成过滤器链(Filter Chain),这些过滤器可以对请求进行拦截和修改,比如添加请求头、参数校验等等,有点像净化污水。然后将请求转发到实际的后端服务。这些过滤器逻辑上可以称作 Pre-Filters,Pre 可以理解为"在...之前"。
- 在请求被路由到后端服务之前,API Gateway可以执行身份验证(如JWT、OAuth等)和授权检查。如果验证失败,Gateway会返回相应的错误信息,终止请求处理。
-
请求转发:API Gateway将经过验证的请求转发给目标微服务。可以添加额外的请求头或修改请求体,以便目标服务可以正确处理请求。
-
微服务响应:微服务处理请求后,将响应返回给API Gateway。响应可能包含状态码、响应头和响应体。
-
响应处理:后端处理完结果后,返回给 Gateway 的过滤器再次做处理,逻辑上可以称作 Post-Filters,Post 可以理解为"在...之后"。
-
API Gateway接收到微服务的响应后,可以进行一些处理,如:
- 错误处理:根据微服务的响应状态码,返回适当的错误信息给客户端。
- 格式转换:将响应数据转换为客户端需要的格式(如从XML转换为JSON)。
- 数据聚合:如果请求涉及多个微服务,Gateway可以将这些服务的响应数据聚合成一个统一的响应。
-
-
返回响应给客户端:经过过滤处理后,API Gateway将最终的响应返回给客户端。客户端可以根据响应的状态码和数据进行后续处理。
额外功能
- 日志记录与监控:API Gateway通常会记录所有的请求和响应,以便进行监控和分析,帮助开发团队追踪API的使用情况和性能问题。
- 速率限制:为了防止滥用,API Gateway可以实施速率限制,控制某一客户端在一定时间内的请求次数。
- 缓存:API Gateway可以缓存某些请求的响应,以提高性能,减少后端服务的负担。
三、比较
Gateway 和 Nginx 都是常见的反向代理服务器,它们的相同点和不同点如下:
相同点:
- 都可以作为反向代理服务器,接收来自客户端的请求并转发到后端服务器进行处理。
- 都支持负载均衡、缓存、SSL 加密等常见的 Web 服务特性。
- 都可以提高 Web 应用的性能、可靠性和安全性。
不同点:
- 功能不同:Gateway 是 Spring Cloud 生态中的网关组件,提供了路由、过滤、限流、熔断等功能,而 Nginx 是一个通用的 Web 服务器,提供了反向代理、负载均衡、缓存、Web 加速、安全控制等功能。
- 架构不同:Gateway 是基于 Spring Cloud 和 Spring Boot 构建的微服务网关,可以与 Spring Cloud 微服务框架无缝集成,而 Nginx 则是一个独立的 Web 服务器,可以与各种 Web 框架集成。
- 配置方式不同:Gateway 通过 Java 代码或 YAML 配置文件来定义路由规则和过滤器链,而 Nginx 则使用 Nginx.conf 配置文件来配置反向代理、负载均衡、缓存等功能。
- 性能不同:Gateway 是基于 Java 和 Spring Boot 构建的,相对于 Nginx 来说性能可能会有一些损失。而 Nginx 是一个经过大量优化的 C 语言程序,性能非常出色。
- 扩展性不同:Gateway 可以通过 Spring Cloud 的插件机制来扩展其功能,而 Nginx 可以通过编写 Nginx 模块来扩展其功能。
综上所述,Gateway 和 Nginx 都是非常优秀的反向代理服务器,具有各自的优势和应用场景。在选择使用哪个反向代理服务器时,需要根据具体的需求和应用场景来进行权衡和选择。
选择建议
Nginx和API Gateway在现代应用架构中各自扮演着重要角色。Nginx主要关注于高性能的反向代理和负载均衡,而API Gateway则负责API的管理、路由、安全和监控。根据项目需求,可以选择使用其中一个或结合两者的优势。
如果项目是一个传统的Web应用,或者需要处理大量的静态内容,同时需要基础的反向代理和负载均衡功能,Nginx可能是更好的选择。
对于基于微服务架构的系统,特别是那些已经采用Spring Cloud全家桶的项目,Spring Cloud Gateway因其强大的API管理功能和与Spring生态的紧密集成而更为适合。
如果应用场景需要在API层面实现复杂逻辑,如动态路由、细粒度的鉴权和过滤等,Spring Cloud Gateway能够提供更灵活的解决方案。
在某些情况下,两者也可以结合使用,Nginx作为最外层的反向代理处理静态内容和初步的负载均衡,而Spring Cloud Gateway则部署在内部作为微服务的入口,处理更精细的API管理任务。
上图的流程就是,客户端先将请求发送给 Nginx,然后转发到网关,网关经过断言匹配到一个路由后,将请求转发给指定 uri,这个 uri 可以配置成微服务的名字,比如 passjava-member。
那么这个服务名具体要转发到哪个 IP 地址和端口上呢?这个就依赖注册中心的注册表了,Gateway 从注册中心拉取注册表,就能知道服务名对应具体的 IP + 端口,如果一个服务部署了多台机器,则还可以通过负载均衡进行请求的转发。