Spring Cloud Gateway限流
在Spring Cloud Gateway中,有Filter過濾器,因此可以在“pre”型別的Filter中自行實現上述三種過濾器。需要JAVA Spring Cloud大型企業分散式微服務雲構建的B2B2C電子商務平臺原始碼 一零三八七七四六二六,但是限流作為閘道器最基本的功能,Spring Cloud Gateway官方就提供了RequestRateLimiterGatewayFilterFactory這個類,適用Redis和lua指令碼實現了令牌桶的方式。
具體原始碼不打算在這裡講述,讀者可以自行檢視,程式碼量較少,先以案例的形式來講解如何在Spring Cloud Gateway中使用內建的限流過濾器工廠來實現限流。
首先在工程的pom檔案中引入gateway的起步依賴和redis的reactive依賴,程式碼如下:
<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>
複製程式碼
在配置檔案中做以下的配置:
server:
port: 8081
spring:
cloud:
gateway:
routes:
- id: limit_route
uri: http://httpbin.org:80/get
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
filters:
- name: RequestRateLimiter
args:
key-resolver: '#{@hostAddrKeyResolver}'
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 3
application:
name: gateway-limiter
redis:
host: localhost
port: 6379
database: 0
複製程式碼
在上面的配置檔案,指定程式的埠為8081,配置了 redis的資訊,並配置了RequestRateLimiter的限流過濾器,該過濾器需要配置三個引數:
burstCapacity,令牌桶總容量。
replenishRate,令牌桶每秒填充平均速率。
key-resolver,用於限流的鍵的解析器的 Bean 物件的名字。它使用 SpEL 表示式根據#{@beanName}從 Spring 容器中獲取 Bean 物件。
KeyResolver需要實現resolve方法,比如根據Hostname進行限流,則需要用hostAddress去判斷。實現完KeyResolver之後,需要將這個類的Bean註冊到Ioc容器中。
public class HostAddrKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
@Bean
public HostAddrKeyResolver hostAddrKeyResolver() {
return new HostAddrKeyResolver();
}
複製程式碼
可以根據uri去限流,這時KeyResolver程式碼如下:
public class UriKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getURI().getPath());
}
}
@Bean
public UriKeyResolver uriKeyResolver() {
return new UriKeyResolver();
}
複製程式碼
也可以以使用者的維度去限流:
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
複製程式碼
用jmeter進行壓測,配置10thread去迴圈請求lcoalhost:8081,迴圈間隔1s。從壓測的結果上看到有部分請求通過,由部分請求失敗。通過redis客戶端去檢視redis中存在的key。如下:
可見,RequestRateLimiter是使用Redis來進行限流的,並在redis中儲存了2個key。