限流,就是在某个时间窗口对资源访问做次数限制,如设定每秒最多100个访问请求。限流具有两个维度,如下
- 时间:基于某段时间范围或某个时间点,即时间窗口,如对每分钟、每秒钟的时间窗口做限制;
- 资源:基于可用资源的限制,如设定最大 访问次数或最高可用连接数;
在实际开发中,不止设置一种限流规则,而是设置多个限流规则共同作用,常见限流规则如下
- QPS和连接数限制:对于QPS和连接数限流,可设定IP维度的限流,也可设定单个服务的限流。如设定一个IP每秒访问次数小于10,连接数小于5,单个服务QPS小于100,连接数小于200等;
- 传输速率:如下载速度100k/s、100m/s;
- 黑白名单:黑名单是限制其访问,白名单是自由访问;
限流常见方法如下
- 令牌桶算法:获取令牌的请求才会被处理,其他请求要么排队要么直接被丢弃,桶存放指定的令牌数;
- 漏桶算法:漏桶是将请求放到桶里,若是桶满了,其他请求将被丢弃,桶里的请求以恒定的速率从桶内流出;
- 滑动窗口:当时间窗口的跨度越长,限流效果越平滑;
在springboot工程中,通过aop的方式实现限流,应用场景有采用guava的速率限流、采用redis的指定时间指定次数限制、socket请求限制、http请求限制。
实例1:guava速率限流
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
//默认每秒桶中漏掉的token
int limit() default 10;
}
@Aspect
@Component
public class RateLimitAspect {
/**
* 用来存放不同接口的RateLimiter(key为接口名称,value为RateLimiter)
*/
private ConcurrentHashMap<String, RateLimiter> map = new ConcurrentHashMap<>();
private RateLimiter rateLimiter;
@Pointcut("@annotation(com..annotation.RateLimit)")
public void limitPointCut() {
}
@Around("limitPointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
RateLimit annotation = methodSignature.getMethod().getAnnotation(RateLimit.class);
int limit = annotation.limit();
// 注解所在方法名区分不同的限流策略
String key = methodSignature.getName();
//获取rateLimiter
if (!map.containsKey(key)) {
map.put(key, RateLimiter.create(limit-1));
}
rateLimiter = map.get(key);
if (rateLimiter.tryAcquire()) {
//执行方法
return joinPoint.proceed();
} else {
System.out.println("在1秒内已经超过" + limit + "次请求,不再向下发起请求.");
return null;
}
}
}
@RateLimit(limit = 3)
@GetMapping(value = "/hello2", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> hello2() {
String result = testService.hello();
return ResponseEntity.ok("每秒内只接受3个请求:" + System.currentTimeMillis() + result);
}

实例2:redis指定时间指定次数限制
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {
int limit() default 10;
int time() default 10;
}
@Aspect
@Component
public class RequestLimitAspect {
private final HttpServletRequest request;
private final RedisService redisService;
@Au

本文介绍了在SpringBoot中如何使用AOP实现限流,包括基于Guava的速率限流、Redis的指定时间指定次数限制,以及Socket请求和HTTP请求的限流。同时,展示了如何设置多个限流规则,以及使用@Order注解来控制切面执行顺序,确保限流策略的有序执行。此外,还探讨了限流在实际应用中的重要性和多种限流方法的适用场景。
最低0.47元/天 解锁文章
1849





