在大数据量高并发访问时,经常会出现服务或接口面对暴涨的请求而不可用的情况,甚至引发连锁反映导致整个系统崩溃。此时你需要使用的技术手段之一就是限流,当请求达到一定的并发数或速率,就进行等待、排队、降级、拒绝服务等。在限流时,常见的两种算法是漏桶和令牌桶算法算法
令牌桶算法
令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。 当桶满时,新添加的令牌被丢弃或拒绝。
1: guava实现
1: 引入pom文件
1 2 3 4 5
| <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>18.0</version> </dependency>
|
2: 创建接口拦截注解
1 2 3 4 5 6
| @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface GuavaRateLimit {
}
|
3: 添加拦截器,针对所有带此注解的接口进行限流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @Aspect @Component public class RateLimitAspect {
private final static Logger logger = LoggerFactory.getLogger(RateLimitAspect.class);
private static final RateLimiter RATE_LIMITER = RateLimiter.create(10/2);
@Around("@annotation(com.example.ratelimit.annotation.GuavaRateLimit)") public Object rateLimiter(ProceedingJoinPoint joinPoint) { Object obj = null; try { if (RATE_LIMITER.tryAcquire()) { obj = joinPoint.proceed(); } else { logger.info("系统繁忙"); return "系统繁忙"; } } catch (Throwable e) { e.printStackTrace(); } return obj; }
}
|
4: 添加限流测试接口
1 2 3 4 5 6 7 8 9 10 11
|
@GuavaRateLimit @PostMapping(value = "/guava") public String guava() { logger.info("guava-limit-test:success"); return "guava-limit-test:success"; }
|
2: redission限流器实现
1: 引入pom文件
1 2 3 4 5
| <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.13.6</version> </dependency>
|
2: 创建接口拦截注解
1 2 3 4 5 6
| @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RedisRateLimit {
}
|
3: 初始化RRateLimiter限流器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private String name = "rateLimiter";
private long rate = 10;
private long rateInterval = 1;
@Bean public RRateLimiter create() { RRateLimiter rateLimiter = redissonClient.getRateLimiter(name); if (rateLimiter.isExists()) { rateLimiter.delete(); } rateLimiter.trySetRate(RateType.PER_CLIENT, rate, rateInterval, RateIntervalUnit.SECONDS); return rateLimiter; }
|
4: 添加拦截器,针对所有带此注解的接口进行限流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @Aspect @Component public class RateLimitAspect {
private final static Logger logger = LoggerFactory.getLogger(RateLimitAspect.class);
@Resource RRateLimiter rRateLimiter;
@Around("@annotation(com.example.ratelimit.annotation.RedisRateLimit)") public Object rRateLimiter(ProceedingJoinPoint joinPoint) { Object obj = null; try { if (rRateLimiter.tryAcquire()) { obj = joinPoint.proceed(); } else { logger.info("系统繁忙"); return "系统繁忙"; } } catch (Throwable e) { e.printStackTrace(); } return obj; }
}
|
5: 添加限流测试接口
1 2 3 4 5 6 7 8 9 10 11
|
@RedisRateLimit @PostMapping(value = "/redis") public String redis() { logger.info("redis-limit-test:success"); return "redis-limit-test:success"; }
|
项目源码地址 https://gitee.com/loveUUxad/ratelimit.git