5.1 微服务网关简介
第三章我们介绍了通过Spring Cloud LoadBalancer实现了微服务之间的调⽤和负载均衡,以及使⽤Spring Cloud OpenFeign声明式调⽤,那我们的各种微服务⼜要如何提供给外部应⽤调⽤呢?
当然,因为是REST API接⼝,外部客户端直接调⽤各个微服务是没有问题的。但出于种种原因,这并不是⼀个好的选择。让客户端直接与各个微服务通讯,会存在以下⼏个问题。
-
客户端会多次请求不同的微服务,增加了客户端的复杂性。
-
存在跨域请求,在⼀定场景下处理会变得相对⽐较复杂。
-
实现认证复杂,每个微服务都需要独⽴认证。
-
难以重构,项⽬迭代可能导致微服务重新划分。如果客户端直接与微服务通讯,那么重构将会很难实施。
-
如果某些微服务使⽤了防⽕墙、浏览器不友好的协议,直接访问会有⼀定困难。
面对类似上⾯的问题,我们要如何解决呢?答案就是:服务⽹关!在微服务系统中微服务资源⼀般不直接暴露给我外部客户端访问,这样做的好处是将内部服务隐藏起来,从⽽解决上述问题。
网关有很多重要的意义,具体体现在下⾯⼏个⽅⾯。
-
⽹关可以做⼀些身份认证、权限管理、防⽌⾮法请求操作服务等,对服务起⼀定保护作⽤。
-
⽹关将所有微服务统⼀管理,对外统⼀暴露,外界系统不需要知道微服务架构个服务相互调⽤的复杂性,同时也避免了内部服务⼀些敏感信息泄露问题。
-
易于监控。可在微服务⽹关收集监控数据并将其推送到外部系统进⾏分析。
-
客户端只跟服务⽹关打交道,减少了客户端与各个微服务之间的交互次数。
-
多渠道⽀持,可以根据不同客户端(WEB端、移动端、桌⾯端...)提供不同的API服务⽹关。
-
⽹关可以⽤来做流量监控。在⾼并发下,对服务限流、降级。
-
⽹关把服务从内部分离出来,⽅便测试。
微服务⽹关能够实现,路由、负载均衡等多种功能。类似Nginx,反向代理的功能。在微服务架构中,后端服务往往不直接开放给调⽤端,⽽是通过⼀个API⽹关根据请求的URL,路由到相应的服务。当添加API⽹关后,在第三⽅调⽤端和服务提供⽅之间就创建了⼀⾯墙,在API⽹关中进⾏权限控制,同时API⽹关将请求以负载均衡的⽅式发送给后端服务。
5.2 Spring Cloud Gateway简介
5.2.1 简介
SpringCloud Gateway 是 Spring Cloud 的⼀个全新项⽬,该项⽬是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的⽹关,它旨在为微服务架构提供⼀种简单有效的统⼀的 API 路由管理⽅式。
SpringCloud Gateway 作为 Spring Cloud ⽣态系统中的⽹关,⽬标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新⾼性能版本进⾏集成,仍然还是使⽤的Zuul 2.0之前的⾮Reactor模式的⽼版本。⽽为了提升⽹关的性能,SpringCloud Gateway是基于WebFlux框架实现的,⽽WebFlux框架底层则使⽤了⾼性能的Reactor模式通信框架Netty。
Spring Cloud Gateway 的⽬标,不仅提供统⼀的路由⽅式,并且基于 Filter 链的⽅式提供了⽹关基本的功能,例如:安全,监控/指标,和限流。
注意:Spring Cloud Gateway 底层使⽤了⾼性能的通信框架Netty。
5.2.2 特征
SpringCloud官⽅,对SpringCloud Gateway 特征介绍如下:
-
基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
-
集成 Spring Cloud DiscoveryClient
-
Predicates 和 Filters 作⽤于特定路由,易于编写的 Predicates 和 Filters
-
具备⼀些⽹关的⾼级功能:动态路由、限流、路径重写
-
集成Spring Cloud DiscoveryClient
-
集成熔断器CircuitBreaker
从以上的特征来说,和Zuul的特征差别不⼤。SpringCloud Gateway和Zuul主要的区别,还是在底层的通信框架上。
简单说明⼀下上⽂中的三个术语:
(1)Filter(过滤器):
和Zuul的过滤器在概念上类似,可以使⽤它拦截和修改请求,并且对下游的响应,进⾏⼆次处理。 过滤器为org.springframework.cloud.gateway.filter.GatewayFilter类的实例。
(2)Route(路由):
网关配置的基本组成模块,和Zuul的路由配置模块类似。⼀个Route模块由⼀个 ID,⼀个⽬标 URI,⼀组断⾔和⼀组过滤器定义。如果断⾔为真,则路由匹配,目标URI会被访问。
(3)Predicate(断⾔):
这是⼀个 Java 8 的 Predicate,可以使⽤它来匹配来⾃ HTTP 请求的任何内容,例如 headers 或参数。断⾔的输⼊类型是⼀个 ServerWebExchange。
5.2.3 入门案例
创建微服务⽹关⼯程05_cloud_gateway。
1.添加依赖
添加依赖Eureka Discovery Client,Spring Cloud Gateway。
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
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.4.9</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lxs.demo</groupId>
<artifactId>05_cloud_gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>05_cloud_gateway</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
</properties>
<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-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</p