一、Gateway 和 Zuul 的区别

Zuul 基于servlet 2.5 (works with 3.x),使用阻塞API。它不支持任何长期的连接,如websocket。

Gateway建立在Spring Framework 5,Project Reactor 和Spring Boot 2 上,使用非阻塞API。支持Websocket,因为它与Spring紧密集成,所以它是一个更好的开发者体验。

为什么 Spring Cloud 最初选择了使用 Netflix 几年前开源的 Zuul 作为网关,之后又选择了自建 Gateway 呢?有一种说法是,高性能版的 Zuul2 在经过了多次跳票之后,对于 Spring 这样的整合专家可能也不愿意再继续等待,所以 Spring Cloud Gateway 应运而生。

本文不对 Spring Cloud Gateway 和 Zuul 的性能作太多赘述,基本可以肯定的是 Gateway 作为现在 Spring Cloud 主推的网关方案, Finchley 版本后的 Gateway 比 zuul 1.x 系列的性能和功能整体要好。

二、快速入门

我们来搭建一个基于 Eureka 注册中心的简单网关,不对 Gateway 的全部功能做过多解读,毕竟官方文档已经写的很详细了,或者可以阅读中文翻译文档

SpringBoot 版本号:2.1.6.RELEASE

SpringCloud 版本号:Greenwich.RELEASE

1. pom.xml

    <dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
  • spring-cloud-starter-gateway:Spring Cloud Gateway 的启动类
  • spring-cloud-starter-netflix-hystrix:Hystrix 作为网关的熔断方案
  • spring-cloud-starter-netflix-eureka-client:将网关纳入 Eureka 注册中心管理
  • spring-boot-starter-data-redis-reactive:限流方案,Spring Cloud Gateway 默认以 redis 实现限流
  • spring-boot-starter-actuator:用来监控 Gateway 的路由信息。

2. application.yml

spring:
application:
name: cloud-gateway
redis:
host: 127.0.0.1
timeout: 3000
password: xxxx
jedis:
pool:
max-active: 8
max-idle: 4
cloud:
gateway:
enabled: true
metrics:
enabled: true
discovery:
locator:
enabled: true
routes:
# 普通服务的路由配置
- id: cloud-eureka-client
uri: lb://cloud-eureka-client
order: 0
predicates:
- Path=/client/**
filters:
# parts 参数指示在将请求发送到下游之前,要从请求中去除的路径中的节数。比如我们访问 /client/hello,调用的时候变成 http://localhost:2222/hello
- StripPrefix=1
# 熔断器
- name: Hystrix
args:
name: fallbackcmd
# 降级处理
fallbackUri: forward:/fallback
# 限流器
# 这定义了每个用户 10 个请求的限制。允许 20 个突发,但下一秒只有 10 个请求可用。
- name: RequestRateLimiter
args:
# SPEL 表达式获取 Spring 中的 Bean,这个参数表示根据什么来限流
key-resolver: '#{@ipKeyResolver}'
# 允许用户每秒执行多少请求(令牌桶的填充速率)
redis-rate-limiter.replenishRate: 10
# 允许用户在一秒内执行的最大请求数。(令牌桶可以保存的令牌数)。将此值设置为零将阻止所有请求。
redis-rate-limiter.burstCapacity: 20
# websocket 的路由配置
- id: websocket service
uri: lb:ws://serviceid
predicates:
- Path=/websocket/**
management:
endpoints:
web:
exposure:
# 开启指定端点
include: gateway,metrics
eureka:
client:
service-url:
defaultZone: http://user:password@localhost:1111/eureka/
  • spring.redis.*: redis 相关配置是为了实现 Gateway 的限流方案。
  • eureka.client.*:eureka 注册中心信息。
  • spring.cloud.gateway.discovery.locator.enabled:将网关配置为基于使用兼容 DiscoveryClient 注册中心注册的服务来创建路由。
  • spring.cloud.gateway.routes.*:配置路由信息
    • id:路由唯一标识
    • uri:路由转发地址,以 lb 开头的路由,会由 ribbon 处理,转发到 cloud-eureka-client 的服务处理。也可配置成 http 的单机路由 — http://localhost:2222
    • order:路由执行顺序(也可理解成过滤器的执行顺序),执行顺序是从小到大执行,较高的值被解释为较低的优先级。
    • predicates:路由断言,匹配访问路径为 "/client/**" 的请求。
    • filters:网关的过滤器配置
  • management.endpoints.web.exposure.include:暴露 actuator 可以访问的端点
    • /actuator/gateway/routes 查看路由列表
    • /actuator/gateway/globalfilters 检索全局路由 — 对所有路由生效
    • /actuator/gateway/routefilters 检索局部路由 — 可配置只对单个路由生效
    • /actuator/gateway/refresh 清理路由缓存
    • /actuator/metrics/gateway.requests 获得路由请求数据

3. GatewayApplication.java

@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication { public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
} /**
* 限流的键定义,根据什么来限流
*/
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
} }

三、过滤器

Spring Cloud Gateway 同 Zuul 类似,有 “pre” 和 “post” 两种方式的 filter。客户端的请求先经过 “pre” 类型的 filter,然后将请求转发到具体的业务服务,收到业务服务的响应之后,再经过“post”类型的filter处理,最后返回响应到客户端。

与 Zuul 不同的是,filter 除了分为 “pre” 和 “post” 两种方式的 filter 外,在 Spring Cloud Gateway 中,filter 从作用范围可分为另外两种,一种是针对于单个路由的 gateway filter,它需要像上面 application.yml 中的 filters 那样在单个路由中配置;另外一种是针对于全部路由的global gateway filter,不需要单独配置,对所有路由生效。

全局过滤器

我们通常用全局过滤器实现鉴权、验签、限流、日志输出等。

通过实现 GlobalFilter 接口来自定义 Gateway 的全局过滤器;通过实现 Ordered 接口或者使用 @Order 注解来定义过滤器的执行顺序,执行顺序是从小到大执行,较高的值被解释为较低的优先级。

    @Bean
@Order(-1)
public GlobalFilter a() {
return (exchange, chain) -> {
log.info("first pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("third post filter");
}));
};
} @Bean
@Order(0)
public GlobalFilter b() {
return (exchange, chain) -> {
log.info("second pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("second post filter");
}));
};
} @Bean
@Order(1)
public GlobalFilter c() {
return (exchange, chain) -> {
log.info("third pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("first post filter");
}));
};
}

优先级最高的 filter ,它的 “pre” 过滤器最先执行,“post” 过滤器最晚执行。

局部过滤器

我们来定义一个 “pre” 类型的局部过滤器:

@Component
public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> { public PreGatewayFilterFactory() {
super(Config.class);
} @Override
public GatewayFilter apply(Config config) {
// grab configuration from Config object
return (exchange, chain) -> {
//If you want to build a "pre" filter you need to manipulate the
//request before calling chain.filter
ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
//use builder to manipulate the request
ServerHttpRequest request = builder.build();
return chain.filter(exchange.mutate().request(request).build());
};
} public static class Config {
//Put the configuration properties for your filter here
}
}

其中,需要的过滤器参数配置在 PreGatewayFilterFactory.Config 中。然后,接下来我们要做的,就是把局部过滤器配置在需要的路由上,根据 SpringBoot 约定大于配置的思想,我们只需要配置 PreGatewayFilterFactory.java 中,前面的参数就行了,即

spring:
cloud:
gateway:
routes:
- id: cloud-eureka-client
uri: lb://cloud-eureka-client
order: 0
predicates:
- Path=/client/**
filters:
- pre

tips:可以去阅读下 Gateway 中默认提供的几种过滤器,比如 StripPrefixGatewayFilterFactory.java 等。

四、动态路由

Spring Cloud Gateway 实现动态路由主要利用 RouteDefinitionWriter 这个 Bean:

public interface RouteDefinitionWriter {

	Mono<Void> save(Mono<RouteDefinition> route);

	Mono<Void> delete(Mono<String> routeId);
}

之前翻阅了网上的一些文章,基本都是通过自定义 controller 和出入参,然后利用 RouteDefinitionWriter 实现动态网关。但是,我在翻阅 Spring Cloud Gateway 文档的时候,发现 Gateway 已经提供了类似的功能:

@RestControllerEndpoint(id = "gateway")
public class GatewayControllerEndpoint implements ApplicationEventPublisherAware { /*---省略前面代码---*/ @PostMapping("/routes/{id}")
@SuppressWarnings("unchecked")
public Mono<ResponseEntity<Void>> save(@PathVariable String id, @RequestBody Mono<RouteDefinition> route) {
return this.routeDefinitionWriter.save(route.map(r -> {
r.setId(id);
log.debug("Saving route: " + route);
return r;
})).then(Mono.defer(() ->
Mono.just(ResponseEntity.created(URI.create("/routes/"+id)).build())
));
} @DeleteMapping("/routes/{id}")
public Mono<ResponseEntity<Object>> delete(@PathVariable String id) {
return this.routeDefinitionWriter.delete(Mono.just(id))
.then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build())))
.onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build()));
} /*---省略后面代码---*/
}

要创建一个路由,发送POST请求 /actuator/gateway/routes/{id_route_to_create},参数为JSON结构,具体参数数据结构:

{
"id": "first_route",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/first"}
}],
"filters": [],
"uri": "http://www.uri-destination.org",
"order": 0
}]

要删除一个路由,发送 DELETE请求 /actuator/gateway/routes/{id_route_to_delete}

五、附录

Spring Cloud 之 Gateway.的更多相关文章

  1. Spring Cloud 之 Gateway 知识点:网关

    Spring Cloud Gateway 是使用 netty+webflux 实现因此不需要再引入 web 模块. Spring Cloud Gateway 提供了一种默认转发的能力,只要将 Spri ...

  2. Spring Cloud Alibaba - Gateway

    Gateway Gateway简介 底层使用Netty框架,性能大于Zuul 配置gateway模块,一般使用yaml格式: server: port: 80 #spring boot actuato ...

  3. Spring Cloud 组件 —— gateway

    Spring Cloud 网关主要有三大模块:route.predicates.filters 其中 filter 最为关键,是功能增强的核心组件. 列举出一些功能组件: 5.6 CircuitBre ...

  4. spring cloud网关gateway

    spring gateway使用基于netty异步io,第二代网关:zuul 1使用servlet 3,第一代网关,每个请求一个线程,同步Servlet,多线程阻塞模型.而spring貌似不想在支持z ...

  5. 微服务架构spring cloud - gateway网关限流

    1.算法 在高并发的应用中,限流是一个绕不开的话题.限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击. 一般开发高并发系统常见的限流有:限制总并发数(比如数据库连接池.线程池). ...

  6. [Spring Cloud实战 | 第六篇:Spring Cloud Gateway+Spring Security OAuth2+JWT实现微服务统一认证授权

    一. 前言 本篇实战案例基于 youlai-mall 项目.项目使用的是当前主流和最新版本的技术和解决方案,自己不会太多华丽的言辞去描述,只希望能勾起大家对编程的一点喜欢.所以有兴趣的朋友可以进入 g ...

  7. Spring Cloud实战 | 最终篇:Spring Cloud Gateway+Spring Security OAuth2集成统一认证授权平台下实现注销使JWT失效方案

    一. 前言 在上一篇文章介绍 youlai-mall 项目中,通过整合Spring Cloud Gateway.Spring Security OAuth2.JWT等技术实现了微服务下统一认证授权平台 ...

  8. Spring Cloud实战: 基于Spring Cloud Gateway + vue-element-admin 实现的RBAC权限管理系统,实现网关对RESTful接口方法权限和自定义Vue指令对按钮权限的细粒度控制

    一. 前言 信我的哈,明天过年. 这应该是农历年前的关于开源项目 的最后一篇文章了. 有来商城 是基于 Spring Cloud OAuth2 + Spring Cloud Gateway + JWT ...

  9. Spring Cloud实战 | 第十一篇:Spring Cloud Gateway 网关实现对RESTful接口权限控制和按钮权限控制

    一. 前言 hi,大家好,这应该是农历年前的关于开源项目 的最后一篇文章了. 有来商城 是基于 Spring Cloud OAuth2 + Spring Cloud Gateway + JWT实现的统 ...

随机推荐

  1. JPA 报错解决方案 com.microsoft.sqlserver.jdbc.SQLServerException: Cannot insert explicit value for identity column in table 'test_db' when IDENTITY_INSERT is set to OFF.

    这种错误插入数据时就是hibernate的自增长字段生成规则应该用native 在字段前加入注解 @GeneratedValue(generator="generator") @G ...

  2. Java动态规划

    1. 介绍 动态规划典型的被用于优化递归算法,因为它们倾向于以指数的方式进行扩展.动态规划主要思想是将复杂问题(带有许多递归调用)分解为更小的子问题,然后将它们保存到内存中,这样我们就不必在每次使用它 ...

  3. Hadoop编程踩坑

    Hadoop踩坑 在hadoop所有组件编程中,遇到在Windows下运行程序出现 java.io.IOException: Could not locate executable null\bin\ ...

  4. Spring注解?啥玩意?

    目录 基础概念:@Bean 和 @Configuration 使用AnnotationConfigApplicationContext 实例化Spring容器 简单的构造 使用register注册IO ...

  5. docker部署asp.net core

    上一篇文章我们成功的在win10上边安装了docker,这篇文章,我们将在docker中部署asp.net core程序, 先来一张运行成功的hello world镇楼 现在开始,首先创建一个asp. ...

  6. 渐进式web应用开发---service worker (二)

    阅读目录 1. 创建第一个service worker 及环境搭建 2. 使用service worker 对请求拦截 3. 从web获取内容 4. 捕获离线请求 5. 创建html响应 6. 理解 ...

  7. 大数据虚拟混算平台Moonbox配置指南

    一.环境准备 已安装Apache Spark 2.2.0(此版本仅支持Apache Spark 2.2.0, 其他Spark 版本后续会兼容) 已安装MySQL并启动,且开启远程访问 各安装节点已经配 ...

  8. os.path.dirname(__file__)

    os.path.dirname(__file__) 返回脚本的路径 描述: 必须实际存在的.py文件,如果直接在命令行执行,则会引发异常NameError: name 'file' is not de ...

  9. 就是要让你彻底学会 @Bean 注解

    @Bean 注解全解析 随着SpringBoot的流行,基于注解式开发的热潮逐渐覆盖了基于XML纯配置的开发,而作为Spring中最核心的bean当然也能够使用注解的方式进行表示.所以本篇就来详细的讨 ...

  10. C# 创建Windows服务demo

    一.准备工作 1.操作系统:Windows 10 X64 2.开发环境:VS2017 3.编程语言:C# 4. .NET版本:.NET Framework 4.5 二.创建Windows Servic ...