SpringCloudGateway筆記(9)-限流

使用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"

GITHUB代碼地址

歡迎關注微信交流
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章