Spring Cloud 体系内的网关技术主要有 Zuul 和 Spring Cloud Gateway。Zuul 是 Netflix 公司开源的产品,也是 Spring Cloud F版本 之前默认使用的服务网关组件,但是随着 Netflix 公司一系列的停更事件,在 Spring Cloud G版本后已经不建议采用 Zuul 技术,官方建议使用 Spring Cloud Gateway 作为默认的网关技术。
微服务架构中网关在哪里?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uiIXanfa-1622468668834)
1. Spring Cloud Gateway简介
Spring Cloud Gateway 是 Spring 体系内的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,在SpringCloud 2.0以上版本中,没有对新版本的Zuul 2.0 以上最新高性能版本进行集成,仍然还是使用Zuul 1.x 非 Reactor 模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架低层则使用了高性能的Reactor模式通信框架Netty。
Spring Cloud Gateway 的目标是提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全、监控/指标和限流。
Spring Cloud Gateway 特性
- 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
- 动态路由
- Predicates 和 Filters 作用于特定路由
- 集成 Hystrix 断路器
- 集成 Spring Cloud DiscoveryClient
- 易于编写的 Predicates 和 Filters
- 限流
- 路径重写
Spring Cloud Gateway 中的相关概念
- Route(路由):这是网关的基本构建块。它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为true,则路由匹配。
- Predicate(断言):参考的是java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
- Filter(过滤器):这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,可以在请求被路由前或者之后对请求和响应进行修改。
Spring Cloud Gateway工作原理
客户端向 Spring Cloud Gateway 发出请求。如果 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。 过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
虚线左边的是 pre 类型过滤器,虚线右边的是 post 类型过滤器,外部请求进来后先经过 pre 类型的过滤器,再发送到代理服务,代理服务响应请求,再次经过 post 过滤器链,最后传递给前端。
Filter在 pre 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在 post 类型过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等。
Spring Cloud Gateway 与 Zuul 对比
- Zuul 是 Netflix 开源的产品,Spring Cloud Gateway 是 Spring 体系内的产品,和 Spring 体系融合更好。
- Zuul1 不支持长连接,比如 WebSockets;Spring Cloud Gateway 支持 WebSockets 等协议。
- 作为一个服务网关产品,Spring Cloud Gateway 考虑更全面一些,增加了 Predicate、限流等技术。
- Zuul1 是基于 Servlet 框架构建,采用的是阻塞和多线程方式,即一个线程处理一次连接请求,这种方式在内部延迟严重、设备故障较多情况下会引起存活的连接增多和线程增加的情况发生。
- Spring Cloud Gateway 基于 Spring 5.0、Spring Boot 2.0 和 Project Reactor 开发,采用了 Netty 实现了异步非阻塞模型,占用资源更小,在性能方面更有优势。
2. Spring Cloud Gateway实践
目前项目 006SpringCloud 已提供了几个模块,都是前面文章的demo:
- eureka注册中心: eureka-server-7001和 eureka-server-7002
- 服务提供者:provider-payment9001 和 provider-payment9002
- …
服务提供者中都提供了接口 “/payment/get/{id}”,返回的是 CommonResult<Payment> 。
@RestController
@RequestMapping("/payment")
public class PaymentController {
private Logger logger = LoggerFactory.getLogger(PaymentController.class);
@Value("${server.port}")
private String serverPort;
@GetMapping(value = "/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
if (id != null && id % 2 == 0) {
Payment payment = Payment.newInstance().setSerial(UUID.randomUUID().toString()).setId(id);
return CommonResult.newInstance().setCode(200).setMessage("查询成功,serverPort:" + serverPort).setData(payment);
} else {
return CommonResult.newInstance().setCode(444).setMessage("没有对应记录,查询ID: " + id).setData(null);
}
}
...
}
目前项目 006SpringCloud 新建模块 gateway-6001,并在 pom.xml 中添加 Spring Cloud Gateway 依赖。
gateway-6001的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">
<parent>
<artifactId>006SpringCloud</artifactId>
<groupId>com.xander</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway-6001</artifactId>
<dependencies>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project