导读:经过前面的章节咱们在微服务层作了限流,而且集成了SpringCloud Gateway,本章主要内容是将限流功能从微服务迁移到网关层。java
Springcloud Gateway 原生限流主要基于过滤器实现,咱们能够直接使用内置的过滤器RequestRateLimiterGatewayFilterFactory
,目前RequestRateLimiterGatewayFilterFactory
的实现依赖于 Redis
,因此咱们还要引入spring-boot-starter-data-redis-reactive
。react
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifatId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
复制代码
spring:
cloud:
gateway:
routes:
- id: account-service
uri: lb://account-service
order: 10000
predicates:
- Path=/account-service/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 3
key-resolver: "#{@ipKeyResolver}"
复制代码
主要是配置三个主要参数:redis
配置Beanspring
/** * 自定义限流标志的key,多个维度能够从这里入手 * exchange对象中获取服务ID、请求信息,用户信息等 */
@Bean
KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
复制代码
咱们以前的章节已经讲过Sentinel的使用方法,若是有不清楚的能够翻看以前的章节,这里主要说一下与SpringCloud gateway的整合。json
Sentinel从 1.6.0 版本开始提供了 Spring Cloud Gateway 的适配模块,能够提供两种资源维度的限流:bootstrap
下面是咱们的整合步骤后端
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
复制代码
因为须要使用 nacos做为sentinel的配置中心,因此也引入了sentinel-datasource-nacos
app
...
spring:
cloud:
sentinel:
transport:
dashboard: 10.0.10.48:8858
eager: true
datasource:
ds:
nacos:
server-addr: 10.0.10.48:8848
data-id: gateway-sentinel-flow
group-id: DEFAULT_GROUP
rule-type: gw-flow
...
复制代码
这里主要是sentinel的相关配置,从nacos配置中心获取 gateway-sentinel-flow
配置文件,限流类型是网关类型gw-flow。ide
在nacos配置管理public页面创建 data-id
为 gateway-sentinel-flow
的配置文件(json格式),给account-service
与product-service
添加限流规则。spring-boot
[
{
"resource": "account-service",
"count": 5,
"grade": 1,
"paramItem": {
"parseStrategy": 0
}
},
{
"resource": "product-service",
"count": 2,
"grade": 1,
"paramItem": {
"parseStrategy": 0
}
}
]
复制代码
配置完成之后启动网关项目,登陆sentinel控制台,查看限流规则:
配置说明:
以客户端IP做为限流因子
public static final int PARAM_PARSE_STRATEGY_CLIENT_IP = 0;
以客户端HOST做为限流因子
public static final int PARAM_PARSE_STRATEGY_HOST = 1;
以客户端HEADER参数做为限流因子
public static final int PARAM_PARSE_STRATEGY_HEADER = 2;
以客户端请求参数做为限流因子
public static final int PARAM_PARSE_STRATEGY_URL_PARAM = 3;
以客户端请求Cookie做为限流因子
public static final int PARAM_PARSE_STRATEGY_COOKIE = 4;
复制代码
屡次经过网关访问account-service
服务进行测试 http://localhost:8090/account/getByCode/javadaily
查看限流效果:
SpringCloud-gateway限流异常默认的实现逻辑为SentinelGatewayBlockExceptionHandler
,能够查看源码发现异常响应的关键代码以下
因为服务后端都是返回JSON的响应格式,因此咱们须要修改原异常响应,将其修改为ResultData
类的响应格式。要实现这个功能只须要写个新的异常处理器而后在SpringCloud GateWay配置类中注入新的异常处理器便可。
CustomGatewayBlockExceptionHandler
public class CustomGatewayBlockExceptionHandler implements WebExceptionHandler {
...
/** * 重写限流响应,改形成JSON格式的响应数据 * @author javadaily * @date 2020/1/20 15:03 */
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
ServerHttpResponse serverHttpResponse = exchange.getResponse();
serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
ResultData<Object> resultData = ResultData.fail(ReturnCode.RC200.getCode(), ReturnCode.RC200.getMessage());
String resultString = JSON.toJSONString(resultData);
DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(resultString.getBytes());
return serverHttpResponse.writeWith(Mono.just(buffer));
}
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
if (exchange.getResponse().isCommitted()) {
return Mono.error(ex);
} else {
return !BlockException.isBlockException(ex) ? Mono.error(ex) : this.handleBlockedRequest(exchange, ex).flatMap((response) -> this.writeResponse(response, exchange));
}
}
...
}
复制代码
你们能够直接复制 SentinelGatewayBlockExceptionHandler
类,而后修改 writeResponse
方法接口
CustomGatewayBlockExceptionHandler
@Configuration
public class GatewayConfiguration {
...
/** * 注入自定义网关异常 */
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public CustomGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the custom block exception handler .
return new CustomGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
...
}
复制代码
spring:
main:
allow-bean-definition-overriding: true
复制代码
{
"message": "服务开启限流保护,请稍后再试!",
"status": 200,
"success": false,
"timestamp": 1579509123946
}
复制代码
各位在使用过程当中若是发现网关层限流不生效,能够以debug模式启动网关服务,而后对网关过滤器 SentinelGatewayFilter
中的filter方法进行调试,我发现sentinel获取到的网关id并非咱们配置的account-service
,而是加了CompositeDiscoveryClient_
前缀,以下图所示:
因此咱们须要修改 gateway-sentinel-flow
的配置,给咱们的resource 也加上前缀,修改完的配置以下:
[{
"resource": "CompositeDiscoveryClient_account-service",
"count": 5,
"grade": 1,
"paramItem": {
"parseStrategy": 0
}
}, {
"resource": "CompositeDiscoveryClient_product-service",
"count": 2,
"grade": 1,
"paramItem": {
"parseStrategy": 0
}
}]
复制代码
经过使用jemter对接口进行测试,发现网关能正常限流
通过以上几步,咱们能够将后端微服务层的限流配置去掉,让网关层承担限流的功能。
好了,各位朋友们,本期的内容到此就所有结束啦,能看到这里的同窗都是优秀的同窗,下一个升职加薪的就是你了! 若是以为这篇文章对你有所帮助的话请扫描下面二维码加个关注。
"转发" 加 "在看",养成好习惯!我们下期再见!
SpringCloud Alibaba 系列文章