前言
spring cloud gateway作为一种简单有效的统一的API路由管理方式,为我们限流措施提供了一个有效的入口。
一. 限流算法
本文从常用的令牌桶限流算法说起,看如何让在网关中做请求限制。羊会在后续文章中和大家探讨一下一些限流算法,并会在后续文章中讨论下分布式环境中如何在网关限流,请大家持续关注我的文章。
二. 创建工程
2.1 创建一个spring cloud gateway工程
(相信大家早已不陌生,此处省略)
2.2 引入Bucket4j依赖
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-core</artifactId>
<version>4.4.1</version>
</dependency>
2.3 创建网关过滤器
@Component
@Slf4j
@RefreshScope
public class IpRegisterFilter implements GlobalFilter, Ordered {
public static final String WARNING_MSG = "访问太频繁了!";
public static final Map<String, Bucket> LOCAL_CACHE = new ConcurrentHashMap<>();
// 令牌桶初始容量3
private Integer CAPACITY = 3;
// 补充桶的时间间隔,即60秒补充一次
private long PERIOD = 60;
// 每次补充token的个数
public static final long REPLENISH = 1;
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain) {
ServerHttpRequest request = serverWebExchange.getRequest();
ServerHttpResponse response = serverWebExchange.getResponse();
if (request.getURI().getPath().contains( "/你的path" )) {
String ip = request.getRemoteAddress().getHostString();
log.info( "访问IP为:{}", ip );
Bucket bucket = LOCAL_CACHE.computeIfAbsent( ip, k -> createNewBucket( ip ) );
log.info( "IP:{} ,令牌通可用的Token数量:{} ", ip, bucket.getAvailableTokens() );
if (bucket.tryConsume( 1 )) {
// 直接放行
return gatewayFilterChain.filter( serverWebExchange );
} else {
//指定编码
response.getHeaders().add( "Content-Type", "text/plain;charset=UTF-8" );
response.setStatusCode( HttpStatus.FORBIDDEN ); // 状态码
byte[] data = WARNING_MSG.getBytes( StandardCharsets.UTF_8 );
DataBuffer wrap = response.bufferFactory().wrap( data );
return response.writeWith( Mono.just( wrap ) );
}
}
return gatewayFilterChain.filter( serverWebExchange );
}
@Override
public int getOrder() {
return 0;
}
private Bucket createNewBucket(String ip) {
Duration replenishDuration = Duration.ofSeconds( PERIOD );
Refill refill = Refill.of( REPLENISH, replenishDuration );
Bandwidth limit = Bandwidth.classic( CAPACITY, refill );
return Bucket4j.builder().addLimit( limit ).build();
}
}
至此,关键部分已完成。相信大家看到限流桶放在了map里,无法在多实例里应用。不要担心,请关注我后续文章,我会和大家探讨下如何在分布式环境中应用限流。