共计 8361 个字符,预计需要花费 21 分钟才能阅读完成。
1.Gateway 简介
2. 为什么有了 zuul,咱们还要用 Gateway
3.Gateway 的三大外围概念
4.Gateway 工作流程
5.Gateway 的简略配置
6.Gateway 通过微服务名实现动静路由
7.Gateway 的 Predicate
8.Gateway 的 Filter
1.Gateway 简介
在理解 gateway 之前,咱们能够先登录官网看一下 gateway 是一个什么样的工具:https://docs.spring.io/spring…。
SpringCloud Gateway 是 Spring Cloud 的一个全新我的项目,它旨在 为微服务架构提供一种简略无效对立 api 路由治理形式。
SpringCloud Gateway 作为 springCloud 生态系统中的网关,指标是 代替 zuul,在 Spring Cloud2.0 以上的版本中,没有对新版本 Zuul 2.0 以上最高性能版本进行集成 ,依然还是应用的 Zuul 1.x 非 Reactor 模式的老版本。而为了晋升网关的性能,SpringCloud Gateway 是 基于 WebFlux 框架实现的,而 WebFlux 框架底层则应用了高性能的 Reactor 模式通信框架 Netty。
Spring Cloud Gateway 的指标提供对立的路由形式且基于 Filter 链的形式提供了网关根本的性能,例如:平安,监控 / 指标,和限流。
说了这么多,咱们可能还是不明确,咱们再把下面的话 精简 一下:
Spring Cloud Gateway 是一款 网关的工具 。在以前的 spring Cloud 版本中,采纳的都是 zuul 网关,然而 2.x 版本中,zuul 的降级始终没有落实到位,spring Cloud 最初本人研发 了一个 Spring cloud gateway 代替 zuul。
Spring Cloud Gateway 的作用:
像反向代理,权限鉴定,流量管制,负载平衡,日志监控等等,它都能做到。
Spring Cloud Gateway 位于咱们零碎的哪个地位?
这是官网给的图例,
咱们从这张图中能够看出,gateway 的地位是一个 比拟靠前的地位 ,起了整个零碎的 流量入口的作用,然而理论生产中,咱们不止一个网关,也是集群模式的,所以就有了上面这张图:
2. 为什么有了 zuul,咱们还要用 Gateway
起因一:zuul 公布太慢,Netflix 的相干组件都进入了保护期,综合思考,还是本人开发一个 Gateway 是一个很现实的抉择。
起因二 :Spring Cloud Gateway 具备以下个性 。
2.1.1) 动静路由 :能匹配任何申请属性
2.1.2)集成 Hystrix 的 断路器性能
2.1.3)集成 Spring Cloud 服务发现性能
2.1.4)有 Predicate(断言)和 Filter(过滤器)性能, 极易编写
2.1.5) 申请限流性能
2.1.6) 反对门路重写
起因三:SpringCloud Gateway 与 Zuul 的区别。
spring Cloud 以前的网关是 zuul
2.2.1)zuul 1.x是一个基于 阻塞 I /O的 api gateway
2.2.2)Zuul 1.x基于 servlet2.5应用阻塞架构 ,所以它 不反对任何长链接,每次 I / O 操作都是从工作线程中抉择一个执行,申请线程被阻塞到工作线程实现,而且底层是 java 实现,jvm 有那种第一次加载较慢的状况,所以zuul 性能不佳。
2.2.3)zuul 2.x 理念更先进 ,想基于 Netty 非阻塞和反对长链接,但 Spring Cloud 目前本人做了一个 Gateway, 所以还没有整合。
2.2.4)Spring Cloud Gateway 还反对 WebSocket,并且与 Spring 严密集成领有更好的开发体验
咱们看一下 zuul 1.x 模型的特点:
在晚期的 zuul 版本中,采纳的是 tomcat 容器 ,也就是 传统的 servlet IO 模型 。
咱们来温习一下 servlet 的生命周期:
servlet 由 servlet 容器进行生命周期的治理。
容器启动的时候 ,会结构 servlet 对象并调用 servlet 的 init() 进行初始化。
容器运行的时候 ,承受申请,为每个申请调配一个线程(从线程池中获取闲暇线程),而后调用 service()。
容器敞开的时候 ,调用 servlet destory() 销毁 servlet。
上述模式的毛病:
servlet 是一个简略的网络 IO 模型,当申请进入 servlet 容器的时候,servlet 容器就会为其绑定一个线程,在并发不高的状况下,这种模型是实用的 ,然而 一旦并发量进步,线程数量就会上涨,而线程资源的代码比拟低廉(上下文切换,内存耗费),重大影响申请的解决工夫。在一些简略的业务场景下,不心愿为每个 request 调配线程,只须要 1 个或者几个线程就能对应极大并发的申请,这种场景下 servlet 的模型就没有劣势。
所以zuul 1.x 是基于 servlet 之上的一个阻塞式处理器,spring 实现了解决所有 request 申请的一个 servlet(DispatcherServlet)并由该阻塞式处理器解决,所以 springcloud zuul 无奈解脱 servlet 模型的弊病。
接下来咱们来看看GateWay 模型:
新的 gateway 模型 采纳了 spring WebFlux 的模型,https://docs.spring.io/spring…
传统的框架,如 spring mvc,struts2, 都是基于 servlet api 和 servlet 容器之上运行的。
然而 servlet3.1 之后有了异步非阻塞的反对,而webFlux 是一个典型的非阻塞异步的框架,它应用了一个 非阻塞的 web 堆栈来解决大量线程的并发性并以更少的硬件资源进行扩大。
3.Gateway 的三大外围概念
3.1)Route(路由)
路由是构建网关的根本模块,由 id,指标 uri,一系列的断言和过滤器组成 ,就相当 于把一个拜访门路转发到另外一个拜访门路,其中蕴含了一系列规定,如果断言为 true 则匹配该路由。
3.2)Predicate(断言)
匹配 HTTP 申请中的所有内容,如果申请与断言相匹配,则进行路由。
3.3)Filter(过滤)
应用过滤器,能够在 申请在路由之前或者之后进行批改。
通过这张流程图能够看出,当一个 web 申请进来后,通过 predicate 匹配条件,就能够定位到真正的服务节点 , 同时在转发过程的前后,通过 filter 进行一些精细化管制。
4.Gateway 工作流程
咱们看看官网是如何介绍它的工作流程的:
客户端向 Spring Cloud Gateway 发出请求,如果网关处理器匹配到了路由 , 就将申请发送到网关处理程序。处理器再通过该申请指定的过滤器链,将申请发送给理论服务,让服务执行业务逻辑,而后返回。
过滤器之间用需先离开是因为咱们能够在发送申请之前和之后运行逻辑。
在 pre 能够用来做参数校验,权限校验,流量监控,日志输入等等
在 post 能够用来做相应内容,响应头的批改,日志的输入,流量监控等等。
5.Gateway 的简略配置
pom:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>cloud-gateway-9000</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cloud-gateway-9000</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- gateway 要排除这个依赖,因为 gateway 曾经自带了 spring-boot-starter-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
yml:
server:
port: 9000
eureka:
instance:
hostname: cloud-gateway #eureka 服务端的实例名称
prefer-ip-address: true #拜访门路能够显示 IP 地址
instance-id: ${spring.cloud.client.ip-address}:${server.port}-cloud-gateway #拜访门路的名称格局
client:
register-with-eureka: true #false 示意不向注册核心注册本人。fetch-registry: true #false 示意本人端就是注册核心,我的职责就是保护服务实例,并不需要去检索服务
service-url:
#集群指向其它 eureka
defaultZone: http://127.0.0.1:8001/eureka/,http://127.0.0.1:8002/eureka/
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: routh1 #payment_route #路由的 ID,没有固定规定但要求惟一,倡议配合服务名
uri: http://localhost:8501 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,门路相匹配的进行路由
而后,咱们通过网关拜访接口,就能够转发过来了:http://localhost:9000/payment…
6.Gateway 通过微服务名实现动静路由
咱们下面只是把 一个接口固定转发给另外一个服务而已 ,然而 服务的端口可能是变动的 , 而且还是集群部署,须要负载平衡的 ,咱们 不可能把服务名加端口号写死,更不可能只转发到一个服务提供者,所以咱们须要通过微服务名称调用 + 负载平衡:
pom:
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册核心动态创建路由的性能,利用微服务名进行路由
routes:
- id: routh1 #payment_route #路由的 ID,没有固定规定但要求惟一,倡议配合服务名
#uri: http://localhost:8501 #匹配后提供服务的路由地址
uri: lb://service-provider #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,门路相匹配的进行路由
7.Gateway 的 Predicate
上述 predicates 只是用来做一个 uri 地址的匹配和转移,其实 predicates 还有许多的作用,Spring Cloud Gateway 蕴含许多内置的 Route Predicate 工厂。这些 Predicate 都与 HTTP 申请的不同属性匹配,比方有以下这些匹配形式:
工夫匹配(某个工夫点前 / 后 / 区间才凋谢这个转发)
- id: routh #payment_route #路由的 ID,没有固定规定但要求惟一,倡议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://service-provider #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,门路相匹配的进行路由
- After=2022-02-05T15:10:03.685+08:00[Asia/Shanghai] # 这个工夫之后再凋谢转发
- Before=2022-02-05T15:10:03.685+08:00[Asia/Shanghai] # 这个工夫之前凋谢转发
- Between=2022-02-02T17:45:06.206+08:00[Asia/Shanghai],2022-03-25T18:59:06.206+08:00[Asia/Shanghai] # 这个工夫区间凋谢转发
cookie(cookie 肯定要带某个参数)
- id: routh #payment_route #路由的 ID,没有固定规定但要求惟一,倡议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://service-provider #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,门路相匹配的进行路由
- Cookie=username,slf
Header 匹配(申请头参数匹配)
- id: routh #payment_route #路由的 ID,没有固定规定但要求惟一,倡议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://service-provider #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,门路相匹配的进行路由
- Header=X-Request-Id, \d+ # 申请头要有 X -Request-Id 属性并且值为整数的正则表达式
申请形式匹配(Get,POST 等等)
- id: routh #payment_route #路由的 ID,没有固定规定但要求惟一,倡议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://service-provider #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,门路相匹配的进行路由
- Method=GET
详情更多能够看官网:https://cloud.spring.io/sprin…
说白了,Predicate 就是为了实现一组匹配规定,让申请过去找到对应的 Route 进行解决。
8.Gateway 的 Filter
咱们看完上述的配置,然而还是发现一个毛病,难不成咱们每个接口都要去配置一遍转发的接口吗?
这个时候,咱们就能够应用 Filter————过滤器!
路由过滤器可用于批改进入的 HTTP 申请和返回的 HTTP 响应,路由过滤器只能指定路由进行应用。
server:
port: 9000
eureka:
instance:
hostname: cloud-gateway #eureka 服务端的实例名称
prefer-ip-address: true #拜访门路能够显示 IP 地址
instance-id: ${spring.cloud.client.ip-address}:${server.port}-cloud-gateway #拜访门路的名称格局
client:
register-with-eureka: true #false 示意不向注册核心注册本人。fetch-registry: true #false 示意本人端就是注册核心,我的职责就是保护服务实例,并不需要去检索服务
service-url:
#集群指向其它 eureka
defaultZone: http://127.0.0.1:8001/eureka/,http://127.0.0.1:8002/eureka/
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册核心动态创建路由的性能,利用微服务名进行路由
routes:
- id: routh1 #payment_route #路由的 ID,没有固定规定但要求惟一,倡议配合服务名
#uri: http://localhost:8501 #匹配后提供服务的路由地址
uri: lb://service-provider/** #匹配后提供服务的路由地址
predicates:
- Path=/gateway/service-provider/** # 断言,门路相匹配的进行路由, 咱们能够通过服务名称来指定接口,这个服务的接口全副转到这个服务的接口上面,并且去掉两个参数
filters:
- StripPrefix=2 # 去掉 path 的 /gateway/service-provider,将尾巴局部接到 url 上,StripPrefix= 几 就是去掉几个参数
更多过滤器请看:https://cloud.spring.io/sprin…