微服务架构
- SpringCloud
服务注册发现:Nacos
服务限流降级:Sentinel
分布配置中⼼:Nacos
分布式事务保证数据一致性:Seata
分布式定时任务:Spring Scheduling Tasks
服务⽹关:SpringCloud Gateway
异步消息削峰填谷:RocketMQ
服务之间调⽤:OpenFeign、Ribbon
链路追踪:Sleuth+Zipkin
技术栈版本控制
序号 | 名称 | 版本 | 用途 | 备注 |
---|---|---|---|---|
1 | openJDK | 21 | Java JDK | |
2 | postgresSQL | 17.4 | 基础数据库 | |
3 | Maven | 3.9.9 | Java第三方依赖包管理工具 | |
4 | springboot | 3.4.3 | Java MVC框架 | |
5 | springcloud | 2024.0.1 | 微服务框架 | |
6 | springcloud Alibaba | 2023.0.3.2 | 阿里巴巴微服务框架扩展 |
组件版本控制
序号 | 名称 | 版本 | 用途 | 备注 |
---|---|---|---|---|
1 | Nacos | 2.5.1 | 服务注册发现、分布配置中⼼ | |
2 | Sentinel | 1.8.8 | 服务限流降级 | 面向云原生微服务的高可用流控防护组件 |
3 | Seata | 2.3.0 | 分布式事务保证数据一致性 |
什么是⽹关
- API Gateway,是系统的唯⼀对外的⼊⼝,介于客户端和服务器端之间的中间层,处理⾮业务功能 提供路由请求、鉴权、监控、缓存、限流等功能
- 统⼀接⼊
智能路由
AB测试、灰度测试
负载均衡、容灾处理
⽇志埋点(类似Nignx⽇志)- 流量监控
限流处理
服务降级- 安全防护
鉴权处理
监控
机器⽹络隔离
主流的⽹关
- zuul:是Netflix开源的微服务⽹关,和
Eureka,Ribbon,Hystrix等组件配合使⽤,依赖组件⽐
较多,性能教差- kong: 由Mashape公司开源的,基于Nginx的API
gateway- nginx+lua:是⼀个⾼性能的HTTP和反向代理服务器,lua
是脚本语⾔,让Nginx执⾏Lua脚本,并且⾼并发、⾮阻塞
的处理各种请求- springcloud gateway: Spring公司专⻔开发的⽹关,替代
zuul
注意:AlibabaCloud对应的⽹关,⽤
SpringCloud官⽅推荐的Gateway
什么是 SpringCloud Gateway
Spring官⽅出品,基于Spring5+Reactor技术开发的⽹关
性能强劲基于Reactor+WebFlux、功能多样基于springboot2.x, 直接可以jar包⽅式运⾏
官⽅⽂档
https://spring.io/projects/spring-cloud-gateway
项目使用
注:这里仅helloworld一下,下一小章节会按实际使用结合nginx使用。
新建微服务online-edu-gateway
建好之后删掉Main.java
配置online-edu-api-gateway/pom.xml
,增加网关依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.online_edu</groupId>
<artifactId>online-edu</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>online-edu-api-gateway</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
</project>
新增并配置online-edu-api-gateway/src/main/java/org/online_edu/GatewayApplication.java
package org.online_edu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication()
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
新增并配置online-edu-api-gateway/src/main/resources/application.yml
.
server:
port: 8888
spring:
application:
name: online-edu-api-gateway
cloud:
gateway:
routes: #数组形式
- id: order-service #路由唯⼀标识
uri: http://127.0.0.1:8000 #想要转发到的地址
order: 1 #优先级,数字越⼩优先级越⾼
predicates: #断⾔ 配置哪个路径才转发
- Path=/order-server/**
filters: #过滤器,请求在传递过程中通过过滤器修改
- StripPrefix=1 #去掉第⼀层前缀
#访问路径 http://localhost:8888/order-server/api/v1/video_order/list
#转发路径 http://localhost:8000/order-server/api/v1/video_order/list
#需要过滤器去掉前⾯第⼀层
启动网关服务online-edu-api-gateway
和订单服务online-edu-order-service
.
浏览器打开http://localhost:8888/order-server/api/v1/video_order/list
gateway整合nacos
- 原先存在的问题
微服务地址写死
负载均衡没做到
实际使用中,我们不可能将微服务的地址和ip写死,而是通过nacos作为注册中心,进行自动的服务发现。
配置online-edu-api-gateway/pom.xml
,增加naocs依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.online_edu</groupId>
<artifactId>online-edu</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>online-edu-api-gateway</artifactId>
<dependencies>
<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 版本后默认移除了 Ribbon,需手动添加 spring-cloud-loadbalancer 依赖以实现 lb:// 负载均衡路由。-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
</dependencies>
</project>
配置online-edu-api-gateway/src/main/resources/application.yml
,增加nacos配置。
server:
port: 8888
spring:
application:
name: online-edu-api-gateway
cloud:
nacos:
discovery:
server-addr: xxx.xxx.xxx.xxx:8848
username: nacos
password: password
gateway:
routes: #数组形式
- id: order-service #路由唯⼀标识
# uri: http://127.0.0.1:8000 #想要转发到的地址
uri: lb://online-edu-order-service # 从nacos获取名称转发,lb是负载均衡轮训策略
order: 1 #优先级,数字越⼩优先级越⾼
predicates: #断⾔ 配置哪个路径才转发
- Path=/order-server/**
filters: #过滤器,请求在传递过程中通过过滤器修改
- StripPrefix=1 #去掉第⼀层前缀
#访问路径 http://localhost:8888/order-server/api/v1/video_order/list
#转发路径 http://localhost:8000/order-server/api/v1/video_order/list
#需要过滤器去掉前⾯第⼀层
discovery:
locator:
enabled: true #开启⽹关拉取nacos的服务
订单服务online-edu-order-service
开启多实例启动。
修改端口再启动一个:
浏览器打开
http://localhost:8888/order-server/api/v1/video_order/list
再次刷新
Gateway⽹关的配置项
以下仅作为网关功能演示。实际使用网关过程中,注意:
⽹关不要加太多业务逻辑,否则会影响性能,务必记住
路由:是⽹关的基本单元,由ID、URI、⼀组
Predicate、⼀组Filter组成,根据Predicate进⾏匹配转发
route组成部分
id:路由的ID
uri:匹配路由的转发地址
predicates:配置该路由的断⾔,通过PredicateDefinition类进⾏接收配置。
order:路由的优先级,数字越⼩,优先级越⾼
交互流程
- 客户端向Spring Cloud Gateway发出请求
- 如果⽹关处理程序映射确定请求与路由匹配
- 则将其发送到⽹关Web处理程序
- 通过特定过滤器链运⾏,前置处理-后置处理
Gateway内置的路由断⾔
什么是Gateway路由断⾔
- Predicate 来源于Java8,接受输⼊参数,返回⼀个布尔值结果
- Spring Cloud Gateway 中 Spring 利⽤ Predicate 的特性实现了各种路由匹配规则
- 转发的判断条件,SpringCloud Gateway⽀持多种⽅式,常⻅如:Path、Query、Method、Header等
- ⽀持多个Predicate请求的转发是必须满⾜所有的Predicate后才可以进⾏路由转发
内置路由断⾔—— RoutePredicateFactory 接⼝实现类
进入idea项目中,ctrl+N,搜索RoutePredicateFactory 类。
按住ctrl+Alt,点击接⼝实现类RoutePredicateFactory 名称,可以查询到下游的实现类:
参数编写规则 XXXRoutePredicateFactory,使⽤XXX作为
参数配置, 例如下⾯
predicates:
- Host=
- Path=
- Method=
- Header=
- Query=
- Cookie=
断言使用举例
比如,某个接口,要求在指定时间定时下线。过后不可以在被访问。
使⽤Before ,只要当前时间⼩于设定时间,路由才会匹配请求
东8区的2025-03-28T01:01:01.000+08:00后,请求不可访问
配置online-edu-api-gateway/src/main/resources/application.yml
server:
port: 8888
spring:
application:
name: online-edu-api-gateway
cloud:
nacos:
discovery:
server-addr: xxx.xxx.xxx.xxx:8848
username: nacos
password: password
gateway:
routes: #数组形式
- id: order-service #路由唯⼀标识
# uri: http://127.0.0.1:8000 #想要转发到的地址
uri: lb://online-edu-order-service # 从nacos获取名称转发,lb是负载均衡轮训策略
order: 1 #优先级,数字越⼩优先级越⾼
predicates: #断⾔ 配置哪个路径才转发
- Path=/order-server/**
- Before=2025-03-28T01:01:01.000+08:00
# - RewritePath=/order-server/(?<remaining>.*), /$\{remaining}
filters: #过滤器,请求在传递过程中通过过滤器修改
- StripPrefix=1 #去掉第⼀层前缀
discovery:
locator:
enabled: true #开启网关拉取nacos的服务
重新运行网关服务,浏览器运行,没问题(运行时,当前北京时间2025年3月27日)
改为Before=2025-03-26T01:01:01.000+08:00
浏览器运行:
例如增加必须传的参数
predicates: #断⾔ 配置哪个路径才转发
- Path=/order-server/**
- Before=2025-03-28T01:01:01.000+08:00
- Query=token
浏览器运行:
Gateway⽹关的过滤器
过滤器⽣命周期
- PRE: 这种过滤器在请求被路由之前调⽤,⼀般⽤于鉴权、限流等
- POST:这种过滤器在路由到微服务以后执⾏,⼀般⽤于修改响应结果,⽐如增加header信息、打点结果⽇志
⽹关过滤器分类
- 局部过滤器GatewayFilter:应⽤在某个路由上,每个过滤器⼯⼚都对应⼀个实现类,并且这些类的名称必须以GatewayFilterFactory 结尾.内置很多全局过滤器,顶级接⼝ GlobalFilter
- 全局过滤器:作⽤全部路由上,内置很多局部过滤器,顶级接⼝ GatewayFilterFactory
⾃定义全局过滤器实现鉴权
自定义实现,本质上就是模仿官方的过滤器,写一个自己的java类。
新建online-edu-api-gateway/src/main/java/org/online_edu/filter/UserGlobalFilter.java
package org.online_edu.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class UserGlobalFilter implements GlobalFilter, Ordered {
/**
* 处理Web请求并(可选地)委托给下一个{@code GatewayFilter}
* 通过给定的{@link GatewayFilterChain}。
*
* @param chain 链提供了一种委托给下一个过滤器的方式
* @param exchange 交换当前服务器交换
* @return {@code Mono<Void>} 表示请求处理完成
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 写业务逻辑
return null;
}
/**
* 获取该对象的顺序值。
* 值越高优先级越低。因此,
* 具有最低值的对象具有最高优先级(在某种程度上)
* 类似于Servlet {@code load-on-startup}值)。
* 相同的顺序值将导致任意的排序位置受影响的对象。
*
* @return 返回排序阙值
* @see #HIGHEST_PRECEDENCE
* @see #LOWEST_PRECEDENCE
*/
@Override
public int getOrder() {
return 0;
}
}
模拟写登录鉴权逻辑,这里引入一个工具包apache-commons-lang3
。
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.17.0</version>
</dependency>
如果拉不下来就手动下载一下。
DremoteRepositories=https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -DgroupId=org.apache.commons -DartifactId=commons-lang3 -Dversion=3.17.0
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 写业务逻辑
String token = exchange.getRequest().getHeaders().getFirst("token");
//TODO 根据业务开发对应的鉴权规则,比如JWT
if (StringUtils.isBlank(token)) {
// 返回401
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
//继续往下执⾏
return chain.filter(exchange);
}
online-edu-api-gateway/src/main/resources/application.yml记得注释掉多余的断言。
server:
port: 8888
spring:
application:
name: online-edu-api-gateway
cloud:
nacos:
discovery:
server-addr: xxx.xxx.xxx.xxx:8848
username: nacos
password: password
gateway:
routes: #数组形式
- id: order-service #路由唯⼀标识
# uri: http://127.0.0.1:8000 #想要转发到的地址
uri: lb://online-edu-order-service # 从nacos获取名称转发,lb是负载均衡轮训策略
order: 1 #优先级,数字越⼩优先级越⾼
predicates: #断⾔ 配置哪个路径才转发
- Path=/order-server/**
# - Before=2025-03-28T01:01:01.000+08:00
# - Query=token
filters: #过滤器,请求在传递过程中通过过滤器修改
- StripPrefix=1 #去掉第⼀层前缀
discovery:
locator:
enabled: true #开启网关拉取nacos的服务
运行:
配置请求,并发送: