SpringCloud Gateway实现微服务网关

对于网关的开发,完全自研的难度比较大,特别是IO的处理。考虑到目前市面上有比较多的成熟框架,可以基于成熟的开源框架,进行二次开发。

对于Java来说,目前Spring提供了SpringCloud Gateway(下面简称SG),SG基于SpringWebFlux,底层默认使用的是Netty框架,支持高并发请求,同时提供了一些默认的组件,支持路由、限流等功能。可以基于SG进行二次开发。

如果对网关有特别多的自定义需求,可以直接基于Netty来进行更彻底的二次开发,适配自身系统的个性化需求。

一、SpringCloud Gateway整体架构

SpringCloud Gateway基于SpringWebFlux,整体架构如下图所示:

SpringCloud Gateway实现微服务网关插图

1、SG定义了几个概念

  • 路由(Route):路由是网关的基本构成单元。它由一个ID、一个目标URL、一组谓词以及一组过滤器组成。当谓词判定为true时,表示请求与对应路由匹配
  • 谓词(Predicate):Java8函数式谓词。输入参数是Spring框架封装的ServerWebExchange对象。开发人员可以基于此对象来匹配HTTP请求的任意内容,比如请求头或请求参数
  • 过滤器(Filter):由特定工厂类构造的一组Spring框架提供的GatewayFilter对象。过滤器可以在请求或响应被处理前/后对其进行修改。

2、SG处理请求的大致流程

GatewayHandlerMapping判定对应的请求是否匹配某个路由。如果匹配到某个路由,则将请求交给GatewayWebHandler处理。Handler调用一个Filter链来处理这个请求,具体执行流程如下:

  • 首先,会执行「pre」过滤器的逻辑
  • 然后执行请求处理逻辑
  • 最后再执行「post」过滤器的逻辑

3、SG提供的过滤器

SG提供了GatewayFilter和GlobalFilter两种类型的过滤器,从名字可以看出GlobalFilter是对全局生效的,而GatewayFilter是对特定请求生效的。

GlobalFilter是针对所有匹配了GatewayHandlerMapping的请求生效,而不是对所有进入网关的请求生效。假设,你在网关中编写了一个Controller,但是路由配置中并没有匹配该Controller的路径,那么针对该Controller的请求并不会触发任何GlobalFilter。

4、SG针对一个请求的完整流程

SG针对一个请求的完整流程如下图所示:

SpringCloud Gateway实现微服务网关插图2

可以看到,SG的扩展是基于一个个的Filter来实现的。前面提到的大部分需求也完全可以基于Filter去实现,包括但不限于路由、负载均衡、认证授权、过载保护、缓存、服务重试、日志记录等。

二、限流实现

SG提供了RequestRateLimiterGatewayFilterFactory过滤器支持限流,同时也支持基于histrix的过载保护,直接集成使用即可,具体请见histrix文档。

1、路由配置

以RequestRateLimiterGatewayFilterFactory为例来分析SG如何基于拦截器来实现j限流的。SG中的限流是针对每个路由来单独定义的,配置内容如下:

SpringCloud Gateway实现微服务网关插图4

上面的配置,配置了一个路由:

  • id为test_route
  • 路由地址到lb://test。前面的lb://表示支持负载均衡,后面的test是服务名称
  • predicates是谓词,表示当请求以/test开头时,此路由生效
  • 同时配置了一个限流拦截器,包括名称和参数。基于此配置通过RequestRateLimiterGatewayFilterFactory来构建对应的Filter。其中的参数是用来配置请求速率的,即每秒允许10个请求,允许短时间(这里是1秒)涌入20个请求。

上面的配置会被构建为一个RouteLocator实例,该类根据配置构建Route、Predicates、Filter等实例。对于Filter来说,

  • 在创建RouteLocator实例时,已创建的GatewayFilterFactory实例列表会被作为参数传入
  • list被转换为map,key为去除了GatewayFilterFactory后缀名的Filter类名(与配置文件中的Filter的配置匹配),value是对应的GatewayFilterFactory实例
  • 在构建Route实例时,会根据配置文件中的Filter的配置获取Filter实例设置进Route实例中,提供给后续流程使用
SpringCloud Gateway实现微服务网关插图6

2、RequestRateLimiterGatewayFilterFactory核心代码

RequestRateLimiterGatewayFilterFactory核心代码如下所示:

SpringCloud Gateway实现微服务网关插图8
  • 1处,获取配置参数。这里的KeyResolver是对获取请求的key逻辑的抽象。比如其中的一个实现是PrincipalNameKeyResolver,它从ServerWebExchange中获取Principal对象,并将Principal.getName()的返回值作为当前请求的key,如果值相同,则认定为同一个请求。
  • 2处,构建匿名GatewayFilter
  • 3处,基于限流器来处理限流逻辑

3、官方提供的分布式限流方案

官方提供的分布式限流方案是基于redis实现。

SpringCloud Gateway实现微服务网关插图10

核心逻辑在RedisRateLimiter的isAllowed()方法中:

SpringCloud Gateway实现微服务网关插图12
  • 1处,获取参数(上面已经解释过了)
  • 2处,构建lua参数,执行lua脚本
  • 3处,根据返回值判定是否允许访问

三、自定义拦截器

要编写一个自定义的GatewayFilter的流程如下:

  • 编写一个FilterFactory类继承AbstractGatewayFilterFactory,这个类实现了GatewayFilterFactory接口,该接口提供了一个名叫name的默认方法,用于提供Factory的name,作为获取对应实例的名称。逻辑就是将对应FilterFactory类名后的「GatewayFilterFactory」去掉,例如上面的RequestRateLimiterGatewayFilterFactory,对应的配置名称就是RequestRateLimiter。
  • 在覆写的apply方法中构建对应的Filter,可以是直接返回匿名GatewayFilter,或返回对应Filter的实例
  • 如果返回的是Filter的实例,则需要编写一个实现了GatewayFilter的Filter类,实现其filter方法
  • 然后将FilterFactory、实现的Filter(如果有的话)配置给Spring管理
  • 最后,就可以在配置文件中针对需要的路由配置对应的Filter了

四、聚合服务

SG基于SpringWebFlux,支持编写异步RESTful接口,同时提供WebClient异步REST客户端来实现聚合服务的编写。不过由于是编码的形式,所以需要发布网关。对于集群部署的情况下,在可用性要求没有特别严格的情况下,此方式可以接受。

如果聚合服务较多且发布频繁,可以独立出聚合服务层。即基于SpringWebFlux构建微服务,使用WebClient来整合独立微服务的逻辑,网关路由至对应的服务即可。

五、非功能性需求

SG本身就基本符合前面提到的非功能性需求:

  • 基于SpringWebFlux的非阻塞IO模型,支持高并发。
  • 基于分布式配置服务进行动态配置
  • 基于GatewayFilter和GlobalFilter进行扩展
  • 可以接入PinPoint的链路监控以及基于ELK的日志监控平台

主要注意保证无状态设计!

发表评论