限流算法整理

漏桶算法和令牌桶算法的区别

“漏桶算法”能够强行限制数据的传输速率 “令牌桶算法”在能够限制数据的平均传输速率外,还允许某种程度的突发传输。
在“令牌桶算法”中,只要令牌桶中存在令牌,那么就允许突发地传输数据直到达到用户配置的门限,因此它适合于具有突发特性的流量。

服务限流之漏桶算法

一个固定的漏桶,以常量固定的速率流出水滴。 如果桶中没有水滴的话,则不会流出水滴
如果流入的水滴超过桶中的流量,则流入的水滴可能会发生溢出,溢出的水滴请求是无法访问的,直接调用服务降级方法,桶中的容量是不会发生变化。

服务限流之令牌桶算法

令牌桶算法是一个存放固定容量令牌的桶,按照固定速率往桶里添加令牌。 令牌桶算法的描述如下:
假设限制2r/s,则按照500毫秒的固定速率往桶中添加令牌; 桶中最多存放b个令牌,当桶满时,新添加的令牌被丢弃或拒绝;
当一个n个字节大小的数据包到达,将从桶中删除n个令牌,接着数据包被发送到网络上;
如果桶中的令牌不足n个,则不会删除令牌,且该数据包将被限流(要么丢弃,要么缓冲区等待)。
在这里插入图片描述

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

/*
 * RateLimiter是guava提供的基于令牌桶算法的实现类,可以非常简单的完成限流特技,并且根据系统的实际情况来调整生成token的速率。
 * 使用RateLimiter 实现令牌通方式限流
 */
@RestController
public class IndexController {
   @Autowired
   private OrderService orderService;
   // create 方法中传入一个参数 以每秒为单位固定的速率值 1r/s 每秒中往桶中存入一个令牌
   RateLimiter rateLimiter = RateLimiter.create(100); // 独立线程

   // 相当于该接口每秒钟时间 只能支持一个客户端访问
   @RequestMapping("/addOrder")
   public String addOrder() {
      // 1.限流处理 限流正常要放在网关 客户端从桶中获取对应的令牌,为什么返回double结果,这个结果表示 从桶中拿到令牌等待时间.
      // 2. 如果获取不到令牌,就会一直等待.设置服务降级处理(相当于配置在规定时间内如果没有获取到令牌的话,直接走服务降级。)
      // double acquire = rateLimiter.acquire();
      //
      // System.out.println("从桶中获取令牌等待的时间:" + acquire);
      // 如果在500毫秒内如果没有获取到令牌的话,则直接走服务降级处理
      boolean tryAcquire = rateLimiter.tryAcquire(500, TimeUnit.MILLISECONDS);
      if (!tryAcquire) {
         System.out.println("别抢了, 在抢也是一直等待的, 还是放弃吧!!!");
         return "别抢了, 在抢也是一直等待的, 还是放弃吧!!!";
      }
      // 2. 业务逻辑处理
      boolean addOrderResult = orderService.addOrder();
      if (addOrderResult) {
         System.out.println("恭喜您,抢购成功! 等待时间:" + rateLimiter.acquire());
         return "恭喜您,抢购成功!";
      }
      return "抢购失败!";
   }
}

服务限流之滑动窗口计数

相比计数实现,滑动窗口实现会更加平滑,能自动消除毛刺。
滑动窗口原理是在每次有访问进来时,先判断前 N 个单位时间内的总访问量是否超过了设置的阈值,并对当前时间片上的请求数 +1。
在这里插入图片描述

服务限流之计数器方式

最简单最容易的一种算法,比如我们要求某一个接口,1分钟内的请求不能超过10次,我们可以在开始时设置一个计数器,每次请求,该计数器+1;
如果该计数器的值大于10并且与第一次请求的时间间隔在1分钟内,那么说明请求过多,如果该请求与第一次请求的时间间隔大于1分钟,并且该计数器的值还在限流范围内,那么重置该计数器。
缺陷:在临界点会存在问题
在这里插入图片描述

/**
 * 功能说明: 纯手写计数器方式<br>
 */
public class LimitService {

   private int limtCount = 60;// 限制最大访问的容量
   AtomicInteger atomicInteger = new AtomicInteger(0); // 每秒钟 实际请求的数量
   private long start = System.currentTimeMillis();// 获取当前系统时间
   private int interval = 60;// 间隔时间60秒

   public boolean acquire() {
      long newTime = System.currentTimeMillis();
      if (newTime > (start + interval)) {
         // 判断是否是一个周期
         start = newTime;
         atomicInteger.set(0); // 清理为0
         return true;
      }
      atomicInteger.incrementAndGet();// i++;
      return atomicInteger.get() <= limtCount;
   }

   static LimitService limitService = new LimitService();

   public static void main(String[] args) {

      ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
      for (int i = 1; i < 100; i++) {
         final int tempI = i;
         newCachedThreadPool.execute(new Runnable() {

            public void run() {
               if (limitService.acquire()) {
                  System.out.println("你没有被限流,可以正常访问逻辑 i:" + tempI);
               } else {
                  System.out.println("你已经被限流呢  i:" + tempI);
               }
            }
         });
      }
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值