- 来系统学习下 lambda 表达式吧 - 掘金 (juejin.cn)
- 来一起学习下 Java 8 的 Stream 流 - 掘金 (juejin.cn)
- WebFlux 初体验 - 掘金 (juejin.cn)
在学习了前面这些前置知识之后,今天终于到了学习 Spring Cloud Gateway
的时候了。
Spring Cloud Gateway
是基于 Spring 5.0、Spring Boot 2.0 和 Project Reactor
等技术开发的网关。所以就有了前置知识 WebFlux
的学习,而学习 WebFlux 又需要 Stream
流和 Lambda
表达式等技术作为前置知识。
从这篇文章开始,将正式开始 微服务系列 的相关技术学习。
话不多说,开始今天的学习。
介绍
Spring Cloud Gateway
Spring Cloud Gateway
是基于Spring
生态系统之上构建的API
网关,包括:Spring 5.x
,Spring Boot 2.x
和Project Reactor
。它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。。
什么是服务网关
API Gateway(APIGW / API 网关)
,顾名思义,是系统对外的唯一入口。API
网关封装了系统内部架构,为每个客户端提供定制的API。 近几年来移动应用与企业间互联需求的兴起。从以前单一的Web应用,扩展到多种使用场景,且每种使用场景对后台服务的要求都不尽相同。 这不仅增加了后台服务的响应量,还增加了后台服务的复杂性。随着微服务架构概念的提出,API网关成为了微服务架构的一个标配组件。
为什么要使用网关
微服务的应用可能部署在不同机房,不同地区,不同域名下。此时客户端(浏览器/手机/软件工具)想 要请求对应的服务,都需要知道机器的具体 IP 或者域名 URL,当微服务实例众多时,这是非常难以记忆的,对 于客户端来说也太复杂难以维护。此时就有了网关,客户端相关的请求直接发送到网关,由网关根据请求标识 解析判断出具体的微服务地址,再把请求转发到微服务实例。这其中的记忆功能就全部交由网关来操作了。
工作流程
客户端向 Spring Cloud Gateway 发出请求。如果 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链(职责链设计模式)来将请求发送到我们实际的服务执行业务逻辑,然后返回。
特征
SpringCloud Gateway 特征如下:
- 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
- 集成 Hystrix 断路器
- 集成 Spring Cloud DiscoveryClient
- Predicates 和 Filters 作用于特定路由,易于编写的 Predicates 和 Filters
- 具备一些网关的高级功能:动态路由、限流、路径重写
- 路径重写
- 限流
- 动态路由
核心概念
路由(Route)
:路由是网关最基础的部分,它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。断言(Predicate)
:Java8 中的断言函数。Spring Cloud Gateway 中的断言函数输入类型是 Spring 5.0 框架中 的 ServerWebExchange。Spring Cloud Gateway 中的断言函数允许开发者去定义匹配来自于 Http Request 中的任 何信息,比如请求头和参数等。过滤器(Filter)
:一个标准的 Spring Web Filter。Spring Cloud Gateway 中的 Filter 分为两种类型,分别是 Gateway Filter 和 Global Filter。过滤器将会对请求和响应进行处理。
上手使用
直接在 idea 中创建 Spring Boot 项目:
pom.xml
文件中自动引入 Spring Cloud Gateway 的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
复制代码
application.yml
配置文件:
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-gateway
uri: http://192.168.1.211:8088/
predicates:
- Path=/ytb/**
复制代码
各字段含义如下:
- id:自定义的路由 ID,保持唯一
- uri:目标服务地址
- predicates:路由条件,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。
- filters:过滤规则,这里没有用到。
上面这段配置的意思就是,配置了一个 id 为 cloud-gateway
的 URI 代理规则,路由的规则为:
当访问地址 http://localhost:8080/ytb/fileType/getFileTypeList 时,会自动转发到地址http://192.168.1.211:8088/ytb/fileType/getFileTypeList
转发到的地址是我的一个测试地址 返回如下:
除了 application.yml
配置之外呐,转发功能同样可以通过代码来实现,我们可以在启动类 GateWayApplication 中添加方法 customRouteLocator()
来定制转发规则。
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
return builder.routes()
.route("path_route", r -> r.path("/ytb/**").uri("http://192.168.1.211:8088/")).build();
}
}
复制代码
这里就用到了我们前置知识中的函数式编程。启动项目访问http://localhost:8080/ytb/fileType/getFileTypeList 地址,我们会得到与上面相同的返回结果。
路由规则
Spring Cloud Gateway
是通过 Spring WebFlux
的 HandlerMapping
做为底层支持来匹配到转发路由,Spring Cloud Gateway
内置了很多 Predicates
工厂,这些 Predicates
工厂通过不同的 HTTP 请求参数来匹配,多个 Predicates
工厂可以组合使用。
Predicate
来源于 Java 8,是 Java 8 中引入的一个函数,Predicate
接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate
组合成其他复杂的逻辑(比如:与,或,非)。可以用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。
下面就看看具体的路由规则吧。
Datetime
匹配日期时间之后发生的请求
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-ytb
uri: http://localhost:9201/
predicates:
- After=2021-02-23T14:20:00.000+08:00[Asia/Shanghai]
复制代码
Cookie
匹配指定名称且其值与正则表达式匹配的cookie
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-ytb
uri: http://localhost:9201/
predicates:
- Cookie=username, ezhang
复制代码
Header
匹配具有指定名称的请求头,\d+
值匹配正则表达式
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-ytb
uri: http://localhost:9201/
predicates:
- Header=X-Request-Id, \d+
复制代码
Host
匹配主机名的列表
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-gateway
uri: https://www.baidu.com
predicates:
- Host=**.baidu.com
复制代码
使用 curl 测试,命令行输入:
curl http://localhost:8080 -H "Host: www.baidu.com"
Method
匹配请求methods的参数,它是一个或多个参数
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-ytb
uri: http://localhost:9201/
predicates:
- Method=GET,POST
复制代码
Path
匹配请求路径
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-ytb
uri: http://localhost:9201/
predicates:
- Path=/system/**
复制代码
上面上手使用的就是用的匹配请求路径。
Query
匹配查询参数
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-ytb
uri: http://localhost:9201/
predicates:
- Query=username, ezhang.
复制代码
RemoteAddr
匹配IP地址和子网掩码
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-ytb
uri: http://localhost:9201/
predicates:
- RemoteAddr=192.168.0.1
复制代码
Weight
匹配权重
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-ytb-v1
uri: http://localhost:9201/
predicates:
- Weight=group1, 8
- id: cloud-ytb-v2
uri: http://localhost:9201/
predicates:
- Weight=group1, 2
复制代码
在开发或者测试的时候,或者线上发布,线上服务多版本控制的时候,需要对服务提供权重路由,最常见的使用就是,一个服务有两个版本,旧版本V1,新版本v2。在线上灰度的时候,需要通过网关动态实时推送,路由权重信息。比如80%的流量走服务v1版本,20%的流量走服务v2版本。
路由配置
在spring cloud gateway
中配置uri
有三种方式,包括
- websocket配置方式
spring:
cloud:
gateway:
routes:
- id: cloud-ytb
uri: ws://localhost:9213/
predicates:
- Path=/ytb/**
复制代码
- http地址配置方式
spring:
cloud:
gateway:
routes:
- id: cloud-ytb
uri: http://localhost:9213/
predicates:
- Path=/ytb/**
复制代码
- 注册中心配置方式
在 uri 的 schema 协议部分为自定义的 lb:
类型,表示从微服务注册中心(如 Nacos
)订阅服务,并且进行服务的路由。
spring:
cloud:
gateway:
routes:
- id: cloud-ytb
uri: lb://cloud-ytb
predicates:
- Path=/ytb/**
复制代码
Spring Cloud Gateway 和 Zuul
spring-cloud-Gateway
是spring-cloud
的一个子项目。而zuul
则是netflix
公司的项目,只是spring将zuul
集成在spring-cloud中使用而已。
因为zuul2.0
连续跳票和zuul1
的性能表现不是很理想,所以催生了spring团队开发了Gateway
项目。
Spring Cloud Gateway 和 Zuul 两者的比较:
- 两者均是web网关,处理的是http请求。
- gateway对比zuul多依赖了spring-webflux,在spring的支持下,功能更强大,内部实现了限流、负载均衡等,扩展性也更强,但同时也限制了仅适合于Spring Cloud套件,而zuul则可以扩展至其他微服务框架中,其内部没有实现限流、负载均衡等。
- gateway很好的支持异步,而zuul仅支持同步,那么理论上gateway则更适合于提高系统吞吐量(但不一定能有更好的性能),最终性能还需要通过严密的压测来决定。
- 从框架设计的角度看,gateway具有更好的扩展性,并且其已经发布了2.0.0的 RELESE 版本,稳定性也是非常好的。
总的来说,在微服务架构,如果使用了Spring Cloud生态的基础组件,则Spring Cloud Gateway相比而言更加具备优势,单从流式编程+支持异步上就足以让开发者选择它了。
对于小型微服务架构或是复杂架构(不仅包括微服务应用还有其他非Spring Cloud服务节点),zuul也是一个不错的选择。
注意:
Spring Cloud Gateway
需要 SpringBoot
和 SpringWebFlux
提供的 Netty
运行,不能打成 war
包放在 Tomcat
中运行,因此在项目当中也没有必要添加 spring-boot-starter-web
依赖。
近期评论