这是我参与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
其他限流规则
- 参数限流:
key-resolver: "#{@parameterKeyResolver}"
@Bean
public KeyResolver parameterKeyResolver()
{
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
- 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
的路由指令RouteHystrixCommand
,RouteHystrixCommand
继承于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/**
在进行测试,会发现返回服务已被降级熔断
,表示降级成功。