版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yingziisme/article/details/94591109
使用SpringCloudGateway的重要功能 – 限流过滤器
网关的重要功能还有限流
SpringCloudGateway提供了一个默认的限流过滤器RequestRateLimiter,默认通过Redis+Lua技术实现高并发和高性能的限流方案,源码参考RedisRateLimiter和META-INF/scripts/request_rate_limiter.lua
实际使用需要引用spring-boot-starter-data-redis-reactive的jar包自动开启该filter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
配置文件配置
- id: spring-cloud-client-demo2
uri: lb://spring-cloud-client-demo
predicates:
- Path=/cloud/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 1
key-resolver: "#{@myKeyResolver}"
自定义key的bean
/**
* 自定义限流标志的key
* exchange对象中获取请求信息,用户信息等
*
* @return key
*/
@Bean
KeyResolver myKeyResolver() {
// return exchange -> Mono.just(System.nanoTime() + "");
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
配置测试请求
@GetMapping("/weight")
public String weight(@RequestParam String param) {
log.info("aaaa: {}", param);
return "aaa";
}
@GetMapping("/rate")
public void rate(@RequestParam int size) {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
HttpEntity httpEntity = new HttpEntity(httpHeaders);
for (int i = 0; i < size; i++) {
demoService.rate(httpEntity);
}
}
@Slf4j
@Service
public class DemoService {
@Autowired
private RestTemplate restTemplate;
@Async
public void rate(HttpEntity httpEntity) {
try {
ResponseEntity<String> responseEntity = restTemplate.exchange(new URI("http://localhost:10001/cloud/demo/weight?param=mt"), HttpMethod.GET, httpEntity, String.class);
log.info("===={}==", responseEntity);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
使用POSTMAN发送请求
GET http://localhost:10001/cloud/demo/rate?size=2
发送请求后 可以到看到后台打印
第一个请求正常响应,而第二个请求抛出了429 Too Many Requests的错误
2019-06-29 22:13:14.161 INFO 1112 --- [nio-8801-exec-5] c.m.d.client.controller.DemoController : aaaa: mt
2019-06-29 22:13:14.190 ERROR 1112 --- [ task-21] .a.i.SimpleAsyncUncaughtExceptionHandler : Unexpected exception occurred invoking async method: public void com.mt.demo.client.service.DemoService.rate(org.springframework.http.HttpEntity)
org.springframework.web.client.HttpClientErrorException$TooManyRequests: 429 Too Many Requests
at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:97) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:122) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:102) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:778) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:736) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:710) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:598) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at com.mt.demo.client.service.DemoService.rate(DemoService.java:31) ~[classes/:na]
at com.mt.demo.client.service.DemoService$$FastClassBySpringCGLIB$$1c9d4507.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_191]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_191]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_191]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_191]
同时在redis用MONITOR命令监控 可以看到redis的数据
1561807184.849478 [1 222.125.214.54:59510] "EVALSHA" "eec77786d43c65f7fd568900b5d2b63b692318dc" "2" "request_rate_limiter.{0:0:0:0:0:0:0:1}.tokens" "request_rate_limiter.{0:0:0:0:0:0:0:1}.timestamp" "1" "1" "1561807184" "1"
1561807184.849534 [1 lua] "get" "request_rate_limiter.{0:0:0:0:0:0:0:1}.tokens"
1561807184.849545 [1 lua] "get" "request_rate_limiter.{0:0:0:0:0:0:0:1}.timestamp"
1561807184.849557 [1 lua] "setex" "request_rate_limiter.{0:0:0:0:0:0:0:1}.tokens" "2" "0"
1561807184.849570 [1 lua] "setex" "request_rate_limiter.{0:0:0:0:0:0:0:1}.timestamp" "2" "1561807184"