限流
介绍
限流就是限制一段时间内,用户访问资源的次数,减轻服务器压力,限流大致分为 两种: 1. IP 限流(5s 内同一个 ip 访问超过 3 次,则限制不让访问,过一段时间才可继续访问)
2. 请求量限流(只要在一段时间内(窗口期),请求次数达到阀值,就直接拒绝后面来的访问了, 过一段时间才可以继续访问)(粒度可以细化到一个 api(url),一个服务)
限流模型
漏斗算法 ,令牌桶算法,窗口滑动算法 计数器算法,本次使用令牌桶算法
Gateway结合redis实现请求量限流
pringCloudGateway已经内置了一个RequestRateLimiterGatewayFilterFactory,我们可以直接使用。注意不是全局过滤,是针对某一个gateway。
目前RequestRateLimiterGatewayFilterFactory的实现依赖于Redis,所以我们还要引入spring-boot-starter-data-redis-reactive。
1.添加依赖(在之前gateway项目基础上)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
2.写配置类
package com.dcits.gatewayserver.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 RequestLimitConfig {
//针对某一个接口ip /doLogin 每一个ip 10s只能访问3次
@Bean
public KeyResolver ipKeyResolver(){
return exchange -> Mono.just(exchange.getRequest().getHeaders().getHost().getHostName());
}
//针对路径限制 /doLogin
//api就是接口 一般将gateway叫api网关
@Bean
public KeyResolver apiKeyResolver(){
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
}
3.修改yml文件
spring:
application:
name: gateway-server
cloud:
gateway:
enabled: true # 只要加了依赖默认开启
routes:
- id: login-service-route # 路由id,保持唯一
uri: http://localhost:8081 # uri同一资源定位符
predicates:
- Path=/doLogin # 匹配规则,只要路径匹配上/doLogin,就往uri转发,并且将路径带上
filters:
- name: RequestRateLimiter # 过滤器名称
args: # 过滤器参数
key-resolver: '#{@ipKeyResolver}' # 通过spel表达式取IOC容器中Bean的值
redis-rate-limiter.replenishRate: 1 # 生成令牌的速度
redis-rate-limiter.burstCapacity: 3 # 桶容量
4.启动测试
此时启动会报错找到两个Bean
解决:
在配置类中加@Primary注解
@Configuration
public class RequestLimitConfig {
//针对某一个接口ip /doLogin 每一个ip 10s只能访问3次
@Bean
@Primary
public KeyResolver ipKeyResolver(){
return exchange -> Mono.just(exchange.getRequest().getHeaders().getHost().getHostName());
}
//针对路径限制 /doLogin
//api就是接口 一般将gateway叫api网关
@Bean
public KeyResolver apiKeyResolver(){
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
}
可以在postman中测试,但是较慢,也可以在浏览器中狂按F5
正常:
狂按F5被限流:
可以看到是按照ip进行限制
换成API限流进行测试
修改ym文件:
spring:
application:
name: gateway-server
cloud:
gateway:
enabled: true # 只要加了依赖默认开启
routes:
- id: login-service-route # 路由id,保持唯一
uri: http://localhost:8081 # uri同一资源定位符
predicates:
- Path=/doLogin # 匹配规则,只要路径匹配上/doLogin,就往uri转发,并且将路径带上
filters:
- name: RequestRateLimiter # 过滤器名称
args: # 过滤器参数
key-resolver: '#{@apiKeyResolver}' # 通过spel表达式取IOC容器中Bean的值
redis-rate-limiter.replenishRate: 1 # 生成令牌的速度
redis-rate-limiter.burstCapacity: 3 # 桶容量
可以看到按照路径限制
Gateway跨域
可以克服Ajax只能同源访问
1.在代码中添加@CrossOrigin
2.写成配置文件
package com.dcits.gatewayserver.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config); return new CorsWebFilter(source);
}
}
3.yml进行配置
spring:
application:
name: gateway-server
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]': #针对哪些路径
allowCredentials: true # 这个是可以携带 cookie
allowedHeaders: '*'
allowedMethods: '*'
allowedOrigins: '*'