10 Spring Cloud - Gateway 网关3

675 阅读3分钟

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

路由配置

spring cloud gateway中配置uri有三种方式,包括

  • websocket配置方式
spring:
  cloud:
    gateway:
      routes:
        - id: demo-api
          uri: ws://localhost:9090/
          predicates:
            - Path=/api/**
  • http地址配置方式
spring:
  cloud:
    gateway:
      routes:
        - id: demo-api
          uri: http://localhost:9090/
          predicates:
            - Path=/api/**
  • 注册中心配置方式
spring:
  cloud:
    gateway:
      routes:
        - id: demo-api
          uri: lb://demo-api
          predicates:
            - Path=/api/**

限流配置

顾名思义,限流就是限制流量。通过限流,我们可以很好地控制系统的 QPS,从而达到保护系统的目的。
常见的限流算法有:计数器算法,漏桶(Leaky Bucket)算法,令牌桶(Token Bucket)算法。

Spring Cloud Gateway官方提供了RequestRateLimiterGatewayFilterFactory过滤器工厂,使用Redis 和Lua脚本实现了令牌桶的方式。

1、添加依赖

<!-- spring data redis reactive 依赖 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2、限流规则,根据URI限流

spring:
  redis:
    host: localhost
    port: 6379
    password: 
  cloud:
    gateway:
      routes:
        # 系统模块
        - id: demo-system
          uri: lb://demo-system
          predicates:
            - Path=/system/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1 # 令牌桶每秒填充速率
                redis-rate-limiter.burstCapacity: 2 # 令牌桶总容量
                key-resolver: "#{@pathKeyResolver}" # 使用 SpEL 表达式按名称引用 bean

提示

StripPrefix=1配置,表示网关转发到业务模块时候会自动截取前缀。

3、编写URI限流规则配置类

package com.demo.gateway.config;

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

/**
 * 限流规则配置类
 */
@Configuration
public class KeyResolverConfiguration
{
    @Bean
    public KeyResolver pathKeyResolver()
    {
        return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
    }
}

4、测试服务验证限流
启动网关服务DemoGatewayApplication.java和系统服务DemoSystemApplication.java
因为网关服务有认证鉴权,可以设置一下白名单/system/**在进行测试,多次请求会发现返回HTTP ERROR 429,同时在redis中会操作两个key,表示限流成功。

request_rate_limiter.{xxx}.timestamp
request_rate_limiter.{xxx}.tokens

其他限流规则

  1. 参数限流:key-resolver: "#{@parameterKeyResolver}"
@Bean
public KeyResolver parameterKeyResolver()
{
	return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
  1. IP限流:key-resolver: "#{@ipKeyResolver}"
@Bean
public KeyResolver ipKeyResolver()
{
	return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}

熔断降级

1、添加依赖。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2、配置需要熔断降级服务

spring:
  redis:
    host: localhost
    port: 6379
    password: 
  cloud:
    gateway:
      routes:
        # 系统模块
        - id: demo-system
          uri: lb://demo-system
          predicates:
            - Path=/system/**
          filters:
            - StripPrefix=1
            # 降级配置
            - name: Hystrix
              args:
                name: default
                # 降级接口的地址
                fallbackUri: 'forward:/fallback'

提示

上面配置包含了一个Hystrix过滤器,该过滤器会应用Hystrix熔断与降级,会将请求包装成名为fallback的路由指令RouteHystrixCommandRouteHystrixCommand继承于HystrixObservableCommand,其内包含了Hystrix的断路、资源隔离、降级等诸多断路器核心功能,当网关转发的请求出现问题时,网关能对其进行快速失败,执行特定的失败逻辑,保护网关安全。

配置中有一个可选参数fallbackUri,当前只支持forward模式的URI。如果服务被降级,请求会被转发到该URI对应的控制器。控制器可以是自定义的fallback接口;也可以使自定义的Handler,需要实现接口org.springframework.web.reactive.function.server.HandlerFunction<T extends ServerResponse>

3、实现添加熔断降级处理返回信息

package com.demo.gateway.handler;

import com.alibaba.fastjson.JSON;
import com.demo.common.core.domain.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.util.Optional;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR;

/**
 * 熔断降级处理
 * 
 */
@Component
public class HystrixFallbackHandler implements HandlerFunction<ServerResponse>
{
    private static final Logger log = LoggerFactory.getLogger(HystrixFallbackHandler.class);

    @Override
    public Mono<ServerResponse> handle(ServerRequest serverRequest)
    {
        Optional<Object> originalUris = serverRequest.attribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
        originalUris.ifPresent(originalUri -> log.error("网关执行请求:{}失败,hystrix服务降级处理", originalUri));
        return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR.value()).contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(JSON.toJSONString(R.fail("服务已被降级熔断"))));
    }
}

4、路由配置信息加一个控制器方法用于处理重定向的/fallback请求

package com.demo.gateway.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import com.demo.gateway.handler.HystrixFallbackHandler;
import com.demo.gateway.handler.ValidateCodeHandler;

/**
 * 路由配置信息
 * 
 */
@Configuration
public class RouterFunctionConfiguration
{
    @Autowired
    private HystrixFallbackHandler hystrixFallbackHandler;

    @Autowired
    private ValidateCodeHandler validateCodeHandler;

    @SuppressWarnings("rawtypes")
    @Bean
    public RouterFunction routerFunction()
    {
        return RouterFunctions
                .route(RequestPredicates.path("/fallback").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                        hystrixFallbackHandler)
                .andRoute(RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                        validateCodeHandler);
    }
}

4、测试服务熔断降级
启动网关服务DemoGatewayApplication.java,访问/system/**在进行测试,会发现返回服务已被降级熔断,表示降级成功。