不会飞的章鱼

熟能生巧,勤能补拙,静能养慧;为而不争,莫向外求,反求诸己;念念不忘,必有回响

【慕聘网】微服务网关Gateway

微服务网关介绍

在单体应用时代,客户端(Client)直接与后端应用交互。但进入微服务架构后,系统被拆分为成百上千个微服务(如用户服务、订单服务、仓储服务…)。

如果让客户端直接与这些微服务通信,会带来巨大的问题:

  1. 复杂性爆炸:客户端需要记录所有微服务的地址(IP:Port),一旦后端重构或迁移,前端必须同步修改。
  2. 安全隐患:所有微服务直接暴露在公网,难以统一进行身份认证(Authentication)和鉴权(Authorization)。
  3. 跨域问题:每个服务都需要单独处理 CORS。

这时候,我们需要一个**微服务网关 (API Gateway)**。

可以将其比喻为“工业园区的传达室”“大门保卫处”
所有外部访客(客户端请求)必须先通过大门(网关)。

  • 保安(鉴权):检查你是否有工牌(Token),防止非法人员进入。
  • 前台(路由):你问“我要去财务部”,她会告诉你“右转上三楼”(将请求转发给 Finance Service)。
  • 围墙(保护):外界无法直接翻墙进入某个具体的办公室(微服务IP不暴露),保护了内部隐私。

微服务网关架构

核心功能

  • **路由转发 (Routing)**:根据请求路径,将请求准确分发到后端微服务。
  • **负载均衡 (Load Balancing)**:配合注册中心,将流量分散到服务的多个实例。
  • **认证鉴权 (Security)**:统一处理登录校验、签名验证。
  • **限流熔断 (Rate Limiting)**:保护后端服务不被突发流量冲垮。

微服务网关选型

市面上主流的网关解决方案主要有以下几种:

1. Nginx / Kong

  • Nginx:高性能反向代理服务器,通过 Lua 脚本(OpenResty)扩展。
  • Kong:基于 Nginx 和 Lua 开发的商业化 API 网关。
  • 优点:性能极高。
  • 缺点:二次开发需要掌握 Lua 语言,对 Java 开发团队不友好;更适合作为流量网关(最前端),而非业务网关。

2. Zuul 1.x (Netflix)

  • 特点:Spring Cloud Netflix 早期的核心组件。
  • 架构:基于 Servlet 2.5,采用阻塞式 I/O (Blocking I/O) 编程模型。
  • 痛点:每个请求占用一个线程。在并发量极高、后端服务响应慢(I/O密集型)的场景下,线程池很容易被耗尽,导致性能急剧下降。且目前已停止维护。

3. Spring Cloud Gateway (推荐)

  • 血统:Spring Cloud 官方推出的第二代网关,旨在替代 Zuul。
  • 架构:基于 Spring Boot 2.x, Spring WebFluxProject Reactor
  • 优势
    • **异步非阻塞 (Non-blocking)**:基于 Netty 运行,使用极少的线程就能处理大量并发请求,资源利用率高。
    • 功能丰富:内置了大量路由断言(Predicates)和过滤器(Filters)。
    • 生态融合:与 Spring Cloud Alibaba (Nacos, Sentinel) 集成极其方便。

结论:在“慕聘网”项目中,我们毫不犹豫地选择 Spring Cloud Gateway

微服务网关端口规范

在微服务开发中,为了避免端口冲突和方便管理,我们需要约定一套清晰的端口规范。

微服务端口规范

我们采用如下的分配策略:

1. 8xxx:系统/网关服务

这部分端口预留给基础设施和网关层。

  • 8888: 配置中心 (Config Server,如果独立部署)
  • 8848: Nacos Server
  • 8000: API Gateway (微服务网关)
  • 8080: Sentinel 控制台

2. 9xxx:公共服务/支撑服务

用于一些通用的、被各个业务线调用的支撑服务。

  • 9000: 接口文档聚合 (Swagger/Knife4j)
  • 9001: 监控平台 (Prometheus/Grafana)
  • 9002: 文件上传服务 (OSS)
  • 9003: 短信服务 (SMS)

3. 6xxx / 7xxx:业务微服务

用于核心业务逻辑的服务。

  • 6001: User Service (用户服务)
  • 6002: Company Service (企业服务)
  • 7001: Order Service (订单服务)
  • 7002: Resume Service (简历服务)

遵循这套规范,开发人员看到端口号就能立刻判断出该服务属于哪一类,极大地降低了沟通成本。

构建微服务网关

既然选定了 Spring Cloud Gateway,接下来我们就动手搭建一个网关微服务。

1. 创建模块

imooc-hire 父工程下创建一个新的 Maven 模块,命名为 gateway

2. 引入依赖 (Critical)

这是最容易踩坑的地方!Spring Cloud Gateway 基于 WebFlux (Netty),而普通的 Spring Boot Web 项目基于 Servlet (Tomcat)。两者不兼容!

如果你的项目中(或者引入的公共模块 hire-common 中)包含 spring-boot-starter-web必须将其排除,否则启动会报错。

gateway/pom.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<dependencies>
<!-- Gateway 核心依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- 负载均衡 (Spring Cloud 2020+ 需要显式引入) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

<!-- 引入通用模块,但必须排除 web 依赖 -->
<dependency>
<groupId>org.imooc</groupId>
<artifactId>hire-common</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>

<!-- Mac M1/M2 芯片架构兼容性处理 (可选) -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver-dns-native-macos</artifactId>
<classifier>osx-aarch_64</classifier>
</dependency>
</dependencies>

3. 启动类配置

由于网关通常不需要直接连接数据库(除非将路由存储在数据库中),我们在启动时可以排除数据库自动配置,加快启动速度。

Application.java:

1
2
3
4
5
6
7
8
9
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class // 排除数据库自动配置
})
@EnableDiscoveryClient // 开启服务注册发现
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

4. 核心配置与路由规则

配置 Nacos 地址、网关端口以及路由规则。这是网关的灵魂所在。

application.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
server:
port: 10022 # 网关端口

spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 193.112.133.110:8848 # Nacos 地址
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能
routes:
# 1. 用户服务路由
- id: userRoute
uri: lb://user-service # lb:// 代表负载均衡,后接服务名
predicates:
- Path=/u/** # 断言:路径以 /u/ 开头则转发

# 2. 企业服务路由
- id: companyRoute
uri: lb://company-service
predicates:
- Path=/c/** # 断言:路径以 /c/ 开头则转发

# 3. 认证服务路由
- id: authRoute
uri: lb://auth-service
predicates:
- Path=/auth/** # 断言:路径以 /auth/ 开头则转发

# 全局跨域配置 (CORS)
globalcors:
cors-configurations:
'[/**]':
allowedOriginPatterns: "*"
allowedMethods: "*"
allowedHeaders: "*"
allowCredentials: true
  • id: 路由的唯一标识。
  • uri: 目标服务地址。使用 lb:// 前缀表示从 Nacos 获取服务列表并进行负载均衡。
  • predicates (断言): 路由匹配规则。最常用的是 Path,表示请求路径匹配该规则时才进行转发。
  • globalcors: 统一解决跨域问题,无需在每个微服务中单独配置。

启动 gateway 服务后,刷新 Nacos 控制台,你应该能看到 gateway 已经成功注册。

负载均衡 (LoadBalancer)

在早期的 Spring Cloud 版本中,我们要实现负载均衡,闭着眼都会选 Ribbon。但随着 Netflix 组件的全面停更,Ribbon 也进入了维护模式。

Spring Cloud 官方推出了自己的替代方案:Spring Cloud LoadBalancer

1. 移除 Ribbon,拥抱 LoadBalancer

在 Spring Cloud 2020.0.0 (Ilford) 版本之后,spring-cloud-starter-netflix-ribbon 已经被彻底移除。如果我们使用新版 Spring Cloud,必须显式引入 LoadBalancer。

我们在构建网关时已经引入了它:

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

2. 在网关中的应用

引入 LoadBalancer 后,Gateway 就能通过服务名(Service ID)解析出具体的服务实例 IP 列表,并根据负载均衡策略(默认轮询)分发请求。

这也是为什么我们在配置路由时(下一章会讲),URI 都是以 lb:// 开头的:

1
uri: lb://user-service
  • lb: 代表 LoadBalancer。
  • user-service: 注册在 Nacos 中的服务名。

Gateway 解析到 lb 协议后,会利用 LoadBalancer 从 Nacos 获取 user-service 的所有健康实例,然后选择一个进行转发,从而实现客户端负载均衡。

------ 本文结束------
如果你喜欢这篇文章,打赏一下让我开心到原地转圈圈~,金额随意,感谢鼓励与支持!