Guava限流

Guava限流

文章目录

  • Guava限流
    • 为什么要做限流
    • 原理
      • 漏桶算法
      • 令牌桶算法
    • 实战

为什么要做限流

通常我们的应用在部署之前都会先进行评估,有多少的调用量,需要多少台机器,能承受多大的流量;但是难免会有流量突然增大的时候,比如某时段某个接口突然遭受攻击,这时候某些机器可能会承受不了这个压力,导致崩溃,从而导致整个系统不可用。在我们的系统中, 会设置一定的阈值,保护我们的系统能正常运行。

通常我们流量控制的策略有:限流、降级、分流

原理

常用的限流算法有两种:令牌桶算法和漏桶算法。

漏桶算法

有一个漏桶,按照固定的出水速率漏水,进水的速率是不确定的,如果桶中的水满了,就会溢出(拒绝请求)。因为桶的容量(能承受的最大流量)是固定的,所以如果进水的速率大于出水的速率,一定时间后,就会导致直接溢出。

漏桶算法示意图

漏桶有两个变量,一个是水桶的大小,另一个是漏洞的大小。

缺点:因为漏桶出水的速率是固定的,所以无论流量是大还是小,出水速率都是不变的,这就缺乏效率了。

令牌桶算法

相比于漏桶算法,令牌桶算法在流量突然激增时,处理请求效率高得多。

有一个令牌桶,每次按照固定速率往里面加令牌,来一个请求,则从令牌桶中拿一个令牌,如果令牌桶中没有令牌,则拒绝请求。

当桶满的时候,新加的令牌就会被丢弃。

Guava限流_第1张图片

如果流量增大的话,我们可以控制添加令牌的速率,这样的话处理请求的效率就上去了,这就是相比漏桶算法更好的地方。

实战

例子主要是通过guava的rateLimiter来做限流:

增加一个注解:

@Inherited
@Documented
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimitAnnotation {
}

对该注解增加一个切面:

@Aspect
@Component
public class RateLimitAop {
  	//限流每秒1次。如果设置为n,则每秒限流为1/n
    private RateLimiter rateLimiter= RateLimiter.create(1);

    @Pointcut(value = "@annotation(cn.tongdun.fp.admin.annotation.RateLimitAnnotation)")
    public void rateLimit(){

    }

    @Around("rateLimit()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Boolean flag = rateLimiter.tryAcquire();
        Object obj = null;
        try {
            if (flag) {
                obj = joinPoint.proceed();
            }else{
                throw new Exception("限流");
            }
        } catch (Throwable e) {
            throw e;
        }
        return obj;
    }
}

使用了该注解的接口,会被拦截:

@RateLimitAnnotation
public void test(Student student) {
  ...
}

你可能感兴趣的:(JAVA,java)