Gateway 概述

SpringCloud Gateway是SpringCloud全新项目,基于Spring5.0+SpringBoot2.0和Project Reactor等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的API的路由管理方式

SpringCloud Gateway作为SpringCloud生态系统中的网关,目标是代替Zuul,为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层使用高性能的Reactor模式通信框架Netty

SpringCloud Gateway的模板提供统一的路由方式且基于Filter链的方式提供网关基本的功能,如:安全、监控/指标、限流

Gateway 能干嘛

  • 反向代理
  • 鉴权
  • 流量控制
  • 熔断
  • 日志监控

架构

异步非阻塞模型

SpringCloud Gateway特性

  • 基于Spring Framework5, Project Reactor和SpringBoot2.0进行构建

  • 动态路由:能够匹配任何请求属性

  • 可以对路由指定Predicate(断言)和Filter(过滤器)
  • 集成Hystrix的断路器功能
  • 集成SpringCloud服务发现功能
  • 易于编写的Predicate(断言)和Filter(过滤器)
  • 请求限流功能
  • 支持路径重写

SpringCloud Gateway与Zuul的区别

在SpringCloud Finchley正式版之前,SpringCloud推荐的网关是Netflix提供的Zuul

  1. Zuul 1.x是一个基于阻塞I/O的API Gateway
  2. Zuul 1.x基于Servlet2.5使用阻塞架构,它不支持任何长连接(如WebSocket)。Zuul类似Nginx设计,每次I/O操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是Nginx以C++实现,Zuul以Java实现,JVM本身有第一次加载较慢的情况,使得Zuul的性能相对较差
  3. Zuul 2.x理念想基于Neety非阻塞和支持长连接,但SpringCloud目前还未整合
  4. SpringCloud Gateway建立在SpringFramework5、Project Reactor和SpringBoot2上,使用非阻塞API
  5. SpringCloud Gateway支持WebSocket,并且与Spring紧密集成

Zuul 1.x 模型

SpringCloud中所集成的Zuul版本,采用的是Tomcat容器,使用传统的Servlet IO处理模型

Servlet是一个简单的网络IO模型,当请求进入servlet container时,servlet container为其绑定一个线程,在并发不高的场景下这种模型是适用的。但是高并发场景下,线程数量会上涨,线程资源有限,影响处理时间。在一些简单业务场景。不希望为每个request分配一个线程,只需要1个或几个线程就能应对极大并发的请求,该场景下servlet模型没有优势。

Zuul 1.x 基于servlet上的一个阻塞处理模型,即spring实现了处理所有request请求的一个servlet(DispatcherServlet)并由该servlet阻塞式处理,具有弊端。

工作流程

路由 Route

路由是构建网关的基本模块,由ID、目标URI,一系列的断言和过滤器组成,如果断言为true,则匹配该路由

断言Predicate

开发人员可以匹配HTTP请求中所有内容,如果请求与断言相匹配则进行路由

过滤Filter

Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改

客户端向SpringCloud Gateway发出请求,然后在Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway Web Handler。Handler再通过指定的过滤器链将请求发送到实际服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(pre)或之后(post)执行业务逻辑

Filter在“pre”类型的过滤器可以做参数校验、权限校验、流量控制、日志输出、协议转换等,在”post”类型的过滤器可以做响应内容、响应头的修改、日志的输出、流量监控等

快速入门

1.新建cloud-gateway-gateway9527

2.引入pom

  • spring-cloud-starter-gateway

3.配置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
server:
port: 9527

spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由

- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
#- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
#- Cookie=username,zzyy
#- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式

eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka

4.添加主启动

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {

public static void main(String[] args) {
SpringApplication.run(GatewayMain9527.class, args);
}
}

5.测试

  1. 启动7001
  2. 启动8001
  3. 启动9527
  4. 访问http://localhost:9527/payment/get/1

配置动态路由

默认情况Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

启动微服务

eureka7001、8001、8002

引入pom

  • spring-cloud-starter-netflix-eureka-client

配置yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route # 路由的ID,没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/p
ayment/get/** # 断言,路径相匹配的进行路由

- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由

注意:

uri的协议为lb,表示启用Gateway的负载均衡功能

lb://serviceName是SpringCloud Gateway在微服务中自动为我们创建的负载均衡uri

测试

访问:http://localhost:9527/payment/lb 8001/8002两个端口切换

常用Predicate

Route Predicate Factories

Filter

路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。SpringCloud中内置了多种路由过滤器,都由GatewayFilter的工厂类产生

生命周期

pre和post

种类

GatewayFilter和GlobalFilter

常用的GatewayFilter

GatewayFilter Factories

自定义过滤器

自定义全局过滤器

1.实现接口GlobalFilter,Ordered

2.案例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Component
public class MyLogGatewayFilter implements GlobalFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*******************来到全局日志过滤器 MyLogGatewayFilter " + new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null) {
log.info("!!!!!用户名为空");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}

return chain.filter(exchange);
}

@Override
public int getOrder() {
return 0;
}
}