限流算法

限流算法--Google的Guava令牌桶

pom依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>29.0-jre</version>
</dependency>

速率限制器 RateLimiter

/**
 * 创建一个限速器,每1秒,产生2.5个令牌 
 */
RateLimiter rateLimiter = RateLimiter.create(2.5, 1, TimeUnit.SECONDS);
 
/**
 * 尝试获取1个令牌,如果没有,会阻塞当前线程。直到获取成功返回。
 * 返回值是,阻塞的秒数
 */
double waitSeconds = rateLimiter.acquire();
 
/**
 * 尝试获取1个令牌,不会阻塞当前线程。
 * 立即返回是否获取成功。
 */
boolean success = rateLimiter.tryAcquire();

重载方法

不论是阻塞获取令牌还是非阻塞获取令牌,它们都有几个重载方法。一看也清楚,就是可以设置获取令牌的数量,以及阻塞的时间

public double acquire(int permits)
 
public boolean tryAcquire(Duration timeout)

public boolean tryAcquire(int permits)

public boolean tryAcquire(long timeout, TimeUnit unit)

public boolean tryAcquire(int permits, long timeout, TimeUnit unit) 

public boolean tryAcquire(int permits, Duration timeout)

拦截器

import java.nio.charset.StandardCharsets;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.http.MediaType;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
import com.google.common.util.concurrent.RateLimiter;
 
public class RateLimiterInterceptor extends HandlerInterceptorAdapter {
 
 private final RateLimiter rateLimiter;
 
 /**
  * 通过构造函数初始化限速器
  */
 public RateLimiterInterceptor(RateLimiter rateLimiter) {
  super();
  this.rateLimiter = rateLimiter;
 }
 
 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  
  if(this.rateLimiter.tryAcquire()) {
   /**
    * 成功获取到令牌
    */
   return true;
  }
 
  /**
   * 获取失败,直接响应“错误信息”
   * 也可以通过抛出异常,通过全全局异常处理器响应客户端
   */
  response.setCharacterEncoding(StandardCharsets.UTF_8.name());
  response.setContentType(MediaType.TEXT_PLAIN_VALUE);
  response.getWriter().write("服务器繁忙");
  return false;
 }
}

拦截器的配置类

import java.util.concurrent.TimeUnit;
 
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
import com.google.common.util.concurrent.RateLimiter;
 
import io.springboot.jwt.web.interceptor.RateLimiterInterceptor;
 
 
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
 
 @Override
 public void addInterceptors(InterceptorRegistry registry) {
  /**
   * test接口,1秒钟生成1个令牌,也就是1秒中允许一个人访问
   */
  registry.addInterceptor(new RateLimiterInterceptor(RateLimiter.create(1, 1, TimeUnit.SECONDS)))
   .addPathPatterns("/test");
 }
 
}

限流算法--漏桶算法

 

  漏桶算法这个名字就很形象,算法内部有一个容器,类似生活用到的漏斗,当请求进来时,相当于水倒入漏斗,然后从下端小口慢慢匀速的流出。不管上面流量多大,下面流出的速度始终保持不变。不管服务调用方多么不稳定,通过漏桶算法进行限流,每10毫秒处理一次请求。因为处理的速度是固定的,请求进来的速度是未知的,可能突然进来很多请求,没来得及处理的请求就先放在桶里,既然是个桶,肯定是有容量上限,如果桶满了,那么新进来的请求就丢弃

限流算法--计数器算法

  确定方法的最大访问量MAX,每次进入方法前计数器+1,将结果和最大并发量MAX比较,如果大于等于MAX,则直接返回;如果小于MAX,则继续执行

限流算法--并发量算法

  确定方法的最大并发量MAX,每次进入方法前计数器+1,将结果和最大并发量MAX比较,如果大于等于MAX,则直接返回;如果小于MAX,则继续执行;退出方法后计数器-1。
比如限制服务的并发访问数是100,而服务处理的平均耗时是10毫秒,那么1分钟内,该服务平均能提供( 1000 / 10 ) * 60 * 100 = 6000 次

限流算法--滑动窗口等算法

 

posted on 2022-01-09 23:38  胡子就不刮  阅读(61)  评论(0编辑  收藏  举报

导航