抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Gateway简介

什么是 API 网关(API Gateway)

分布式服务架构、微服务架构与 API 网关

在微服务架构里,服务的粒度被进一步细分,各个业务服务可以被独立的设计、开发、测试、部署和管理。这时,各个独立部署单元可以用不同的开发测试团队维护,可以使用不同的编程语言和技术平台进行设计,这就要求必须使用一种语言和平 台无关的服务协议作为各个单元间的通讯方式。

API 网关的定义

网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。

API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。

主要功能

其主要功能有:

  • 路由转发

    之前说了「API网关」是内部微服务的对外唯一入口,所以外面全部的请求都会先发到这个「API网关」上,然后由「API网关」来根据不同的请求去路由到不同的微服务节点上。例如可以 根据路径 来转发、也可以 根据参数 来转发。

    并且由于内部微服务实例也会随着业务调整不停的变更,增加或者删除节点,「API网关」可以与「服务注册」模块进行协同工作,保证将外部请求转发到最合适的微服务实例上面去。

  • 负载均衡

    既然「API网关」是内部微服务的单一入口,所以「API网关」在收到外部请求之后,还可以根据内部微服务每个实例的负荷情况进行动态的负载均衡调节。一旦内部的某个微服务实例负载很高,甚至是不能及时响应,则「API网关」就通过负载均衡策略减少或停止向这个实例转发请求。当所有的内部微服务实例都处理不过来的时候,「API网关」还可以采用限流或熔断的形式阻止外部请求,以保障整个系统的可用性。

  • 安全认证

    「API网关」就像是微服务的大门守卫,每一个请求进来之后,都必须先在「API网关」上进行身份验证,身份验证通过后才转发给后面的服务,转发的时候一般也会带上身份信息。

    同时「API网关」也需要对每一个请求进行安全性检查,例如参数的安全性、传输的安全性等等。

  • 日志记录

    既然所有的请求都需要走「API网关」,那么我们就可以在「API网关」上统一集中的记录下这些行为日志。这些日志既可以作为我们后续事件查询使用,也可以作为系统的性能监控使用。

  • 数据转换

    因为「API网关」对外是面向多种不同的客户端,不同的客户端所传输的数据类型可能是不一样的。因此「API网关」还需要具备数据转换的功能,将不同客户端传输进来的数据转换成同一种类型再转发给内部微服务上,这样,兼容了这些请求的多样性,保证了微服务的灵活性。

API 网关的职能

API 网关的分类与功能

Gateway简介

​ Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的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

SpringCloud Gateway 特征

SpringCloud官方,对SpringCloud Gateway 特征介绍如下:

  1. 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0

  2. 集成 Hystrix 断路器

  3. 集成 Spring Cloud DiscoveryClient

  4. Predicates 和 Filters 作用于特定路由,易于编写的 Predicates 和 Filters

  5. 具备一些网关的高级功能:动态路由、限流、路径重写

从以上的特征来说,和Zuul的特征差别不大。SpringCloud Gateway和Zuul主要的区别,还是在底层的通信框架上。

重要概念

Filter(过滤器)

​ 和Zuul的过滤器在概念上类似,可以使用它拦截和修改请求,并且对上游的响应,进行二次处理。过滤器为org.springframework.cloud.gateway.filter.GatewayFilter类的实例。

Route(路由)

​ 网关配置的基本组成模块,和Zuul的路由配置模块类似。一个Route模块由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配,目标URI会被访问。

Predicate(断言)

​ 这是一个 Java 8 的 Predicate,可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。断言的输入类型是一个 ServerWebExchange。

SpringCloud Gateway和架构

​ Spring在2017年下半年迎来了Webflux,Webflux的出现填补了Spring在响应式编程上的空白,Webflux的响应式编程不仅仅是编程风格的改变,而且对于一系列的著名框架,都提供了响应式访问的开发包,比如Netty、Redis等等。

​ SpringCloud Gateway 使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架。

SpringCloud Zuul的IO模型

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

​ 大家知道,servlet由servlet container进行生命周期管理。container启动时构造servlet对象并调用servlet init()进行初始化;container关闭时调用servlet destory()销毁servlet;container运行时接受请求,并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用service()。

​ 弊端:servlet是一个简单的网络IO模型,当请求进入servlet container时,servlet container就会为其绑定一个线程,在并发不高的场景下这种模型是适用的,但是一旦并发上升,线程数量就会上涨,而线程资源代价是昂贵的(上线文切换,内存消耗大)严重影响请求的处理时间。在一些简单的业务场景下,不希望为每个request分配一个线程,只需要1个或几个线程就能应对极大并发的请求,这种业务场景下servlet模型没有优势。

​ 所以Springcloud Zuul 是基于servlet之上的一个阻塞式处理模型,即spring实现了处理所有request请求的一个servlet(DispatcherServlet),并由该servlet阻塞式处理处理。所以Springcloud Zuul无法摆脱servlet模型的弊端。虽然Zuul 2.0开始,使用了Netty,并且已经有了大规模Zuul 2.0集群部署的成熟案例,但是,Springcloud官方已经没有集成改版本的计划了。

Webflux模型

​ Webflux模式替换了旧的Servlet线程模型。用少量的线程处理request和response io操作,这些线程称为Loop线程,而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work线程中执行,而不阻塞的操作依然可以在Loop线程中进行处理,大大提高了Loop线程的利用率。官方结构图:

​ Webflux虽然可以兼容多个底层的通信框架,但是一般情况下,底层使用的还是Netty,毕竟,Netty是目前业界认可的最高性能的通信框架。而Webflux的Loop线程,正好就是著名的Reactor 模式IO处理模型的Reactor线程,如果使用的是高性能的通信框架Netty,这就是Netty的EventLoop线程。

​ 关于Reactor线程模型,和Netty通信框架的知识,是Java程序员的重要、必备的内功,个中的原理,具体请参见尼恩编著的《Netty、Zookeeper、Redis高并发实战》一书,这里不做过多的赘述。

Spring Cloud Gateway的处理流程

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

为什么用Gateway

​ Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。

​ Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。

​ 比如内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。

​ 比如区分了一般的 Filter 和全局 Filter,内置了 20 种 Filter 和 9 种全局 Filter,也都可以直接用。当然自定义 Filter 也非常方便。

和Zuul的区别

spring-cloud-Gatewayspring-cloud的一个子项目。而zuul则是netflix公司的项目,只是spring将zuul集成在spring-cloud中使用而已。
因为zuul2.0连续跳票和zuul1的性能表现不是很理想,所以催生了spring团队开发了Gateway项目。

Zuul
  • 使用的是阻塞式的 API,不支持长连接,比如 websockets。

  • 底层是servlet,Zuul处理的是http请求

  • 没有提供异步支持,流控等均由hystrix支持。

  • 依赖包spring-cloud-starter-netflix-zuul。

Gateway
  • 底层依然是servlet,但使用了webflux,多嵌套了一层框架

  • 依赖spring-boot-starter-webflux和/ spring-cloud-starter-gateway

  • 提供了异步支持,提供了抽象负载均衡,提供了抽象流控,并默认实现了RedisRateLimiter。

相同点
  1. 底层都是servlet

  2. 两者均是web网关,处理的是http请求

不同点
内部实现
  • gateway对比zuul多依赖了spring-webflux,在spring的支持下,功能更强大,内部实现了限流、负载均衡等,扩展性也更强,但同时也限制了仅适合于Spring Cloud套件
  • zuul则可以扩展至其他微服务框架中,其内部没有实现限流、负载均衡等。
是否支持异步
  • zuul仅支持同步
  • gateway支持异步。理论上gateway则更适合于提高系统吞吐量(但不一定能有更好的性能),最终性能还需要通过严密的压测来决定
框架设计的角度

​ gateway具有更好的扩展性,并且其已经发布了2.0.0的RELESE版本,稳定性也是非常好的

性能

​ WebFlux 模块的名称是 spring-webflux,名称中的 Flux 来源于 Reactor 中的类 Flux。Spring webflux 有一个全新的非堵塞的函数式 Reactive Web 框架,可以用来构建异步的、非堵塞的、事件驱动的服务,在伸缩性方面表现非常好。使用非阻塞API。 Websockets得到支持,并且由于它与Spring紧密集成,所以将会是一个更好的 开发 体验。
​ Zuul 1.x,是一个基于阻塞io的API Gateway。Zuul已经发布了Zuul 2.x,基于Netty,也是非阻塞的,支持长连接,但Spring Cloud暂时还没有整合计划。

Gateway搭建

注意:gateway搭建可能出现不兼容的情况,各种少方法,经调整 springboot 2.2.5 和 springcloud Hoxton.SR4是兼容的 和 gateway也是兼容的

1
2
<spring-boot.version>2.2.5.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR4</spring-cloud.version>

导入POM依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</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.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>

引入了依赖默认即开启gateway了,如果暂时不想使用这个功能,这可以配置spring.cloud.gateway.enabled=false即可。

注意:Spring Cloud Gateway使用的是Spring Boot和Spring Webflux提供的Netty底层环境,不能和传统的Servlet容器一起使用,也不能打包成一个WAR包。

配置文件配置

bootstrap

bootstrap.properties 的配置文件主要是连接配置中心拉取配置

1
2
3
4
5
6
7
8
9
10
#注册中心地址
spring.cloud.config.uri=http://192.168.64.128:8899
#配置文件分支
spring.cloud.config.label=master
# 配置文件名称
spring.cloud.config.name=application,zuul
# 配置文件环境
spring.cloud.config.profile=dev
#如果连接不上获取配置有问题,快速响应失败
spring.cloud.config.fail-fast=true
application

application.yml主要是应用的相关配置

1
2
3
4
5
server: 
port: 9066
spring:
application:
name: gateway-server
配置中心配置

经过以上配置已经完成了,但是配置中心还有一部分配置没有列出来,启动的时候会自动加载,主要是eureka的连接配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#eureka注册地址
eureka.client.serviceUrl.defaultZone=http://admin:admin@192.168.64.128:8888/eureka
#开启Eureka的健康检测
eureka.client.healthcheck.enabled=true
# 续约更新时间间隔,一般设置比续约到期时间少,该配置表示,每隔30秒就向服务端发送心跳。
eureka.lease-renewal-interval-in-seconds=30
# 续约到期时间,可以单独给每个服务设置,如果在90秒(默认)内没有给服务发送心跳,则剔除该服务。
eureka.instance.lease-expiration-duration-in-seconds=90
# 每隔30秒就去注册中心拉取注册表信息。
eureka.client.registry-fetch-interval-seconds=30

#注册时使用ip而不是主机名
eureka.instance.prefer-ip-address=true
#指定此实例的ip
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}

# 开启健康检查
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=ALWAYS

启动类

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

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

启动测试

发现能够正常启动,并且能够注册到注册中心

到此搭建gateway完成。

评论