Spring Gateway - API网关

Spring Gateway是一款简单有效的路由API,基于Filter链实现网关功能,如:安全、监控/埋点、限流等。

Zuul与Gateway区别

Zuul是Netflix开源项目,Spring早期将其集成到Spring Cloud中,做为网关组件。

后因各种原由,Spring推出自己的Gateway项目,就是现在Spring Cloud Gateway。

核心概念

Route/路由

网关基础模块:由一个ID、一个目标URI、一组断言、一组过滤器构成,断言为真则路由匹配。

断言

Predicate是Java 8一个新特性,Predicate函数式接口提供一个test方法,接受一个参数并返回一个布尔值,接口默认提供三个逻辑函数(&、||、!),与其它条件进行组合,Predicate在java stream api中较为常见。

Spring Gataway中的Predicate,参数是一个ServerWebExchange,用于匹配HTTP请求,包括headers和参数。

Spring Gataway内置很多Predicates, Predicates工厂可通过HTTP参数执行匹配,Predicates工厂允许组合使用。

过滤器

过滤器接口:

GatewayFilter

具体实现处理请求和响应,Spring Gateway内置30多种过滤器。

执行流程

终端请求Gateway,Gateway Handler Mapping执行路由匹配,将请求转发给Gateway Web Handler,Handler使用过滤器链处理请求。

路由

Spring Gateway通过一组Predicate定义路由。

路由用法

application.yml:

spring:
 cloud:
  gateway:
   routes:
   - id: between_route
    uri: https://example.org
    predicates:
    - Between=2019-08-23T17:42:47.789-07:00[America/Denver], 2019-08-25T17:42:47.789-07:00[America/Denver]

说明:在2019年08月23日17:42和2019年08月25日17:42之间的请求,会被转发到https://example.org上。

注:07:00[America/Denver]是当地时区,东八区为+08:00[Asia/Shanghai]

示例:

spring:
 cloud:
  gateway:
   routes:
   - id: cookie_route
    uri: https://example.org
    predicates:
    - Cookie=chocolate, ch.p

说明:此路由表示cookie中包含了chocolate和ch.p的请求会被转发到https://example.org。

Spring Gateway内置10多种路由规则,具体参考Spring Route Predicate Factories

路由过滤器

路由过滤器能对HTTP请求和响应做相应的处理。

过滤器作用范围被限定在指定的路径下。

Spring Gateway内置很多GatewayFilterFactory实现。

application.yml

spring:
 cloud:
  gateway:
   routes:
   - id: add_response_header_route
    uri: https://example.org
    filters:
    - AddRequestParameter=foo, bar
    - AddResponseHeader=X-Response-Foo, Bar

说明:为https://example.org路径下的请求添加一个参数foo=bar,在响应的Header中添加一个X-Response-Foo:Bar参数。

并发系统的保护策略通常是:缓存、降级、限流,Spring Gateway提供31种的路由过滤器,其中就包括熔断和限流功能的过滤器。

熔断

Spring Cloud Gateway将Hystrix断路器模式引入网关路由,通过Hystrix GatewayFilter,保护服务免受级联故障的影响。

应用发生故障时会调用fallback,此处Hystrix过滤器fallback Uri参数为可选。

目前仅支持URI forward选项,若fallback被调用,请求将被转发到指定的URI上。

spring:
 cloud:
  gateway:
   routes:
   - id: hystrix_route
    uri: lb://backing-service:8088
    predicates:
    - Path=/consumingserviceendpoint
    filters:
    - name: Hystrix
     args:
      name: fallbackcmd
      fallbackUri: forward:/incaseoffailureusethis
    - RewritePath=/consumingserviceendpoint, /backingserviceendpoint

限流

Spring Gateway使用限流处理类:

org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory

RequestRateLimiterGatewayFilterFactory使用RateLimiter接口下的RedisRateLimiter确认当前请求能否继续,若不能,返回HTTP 429 - Too Many Requests(默认情况下)。

RedisRateLimiter实现是一个令牌桶限流策略(恒定的令牌生成速度,限制单位时间内令牌数量),也可通过实现RateLimiter接口,编写自己的限流算法。

spring:
 cloud:
  gateway:
   routes:
   - id: requestratelimiter_route
    uri: https://example.org
    filters:
    - name: RequestRateLimiter
     args:
      redis-rate-limiter.replenishRate: 10
      redis-rate-limiter.burstCapacity: 20

实现了RateLimiter接口的自定义限流算法,在配置文件中,使用SpEL按名称引用bean,如:#{@myRateLimiter}引用一个名称为myRateLimiter bean。

application.yml

spring:
 cloud:
  gateway:
   routes:
   - id: requestratelimiter_route
    uri: https://example.org
    filters:
    - name: RequestRateLimiter
     args:
      rate-limiter: "#{@myRateLimiter}"
      key-resolver: "#{@userKeyResolver}"

限制请求内容大小

Spring Gateway使用RequestSizeGatewayFilterFactory限制请求内容大小,内容大于指定参数时,RequestSizeGatewayFilterFactory将响应状态设置为413[Payload Too Large],并附加errorMessage。

application.yml

spring:
 cloud:
  gateway:
   routes:
   - id: request_size_route
    uri: http://localhost:8080/upload
    predicates:
    - Path=/upload
    filters:
    - name: RequestSize
     args:
      maxSize: 5000000

大于指定参数时,返回errorMessage :

Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB

动态路由配置

Spring Gateway默认将路由保存在内存中,由InMemoryRouteDefinitionRepository维护,动态路由核心在于自行维护路由,通过事件清除原始数据。

实现RouteDefinitionWriter、RouteDefinitionLocator接口接管路由维护工作,具体存储方案可以是内存、NoSQL。

通过实现ApplicationEventPublisherAware接口:

ApplicationEventPublisher.publishEvent(new RefreshRoutesEvent(this)),清除CachingRouteLocator中的数据。