使用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"
歡迎關注微信交流