漏桶算法与令牌桶算法


转载:本文转载自 linkedkeeper.com (文/张松然)

漏桶算法

漏桶算法:水(请求)先进入到漏桶里,漏桶以一定速度出水,当水流(请求)过大时会直接溢出,可以强行限制数据的传输速率。
在这里插入图片描述

令牌桶算法

令牌桶算法:系统会以恒定速度向令牌桶放入令牌,如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌,则拒绝服务。
在这里插入图片描述

区别

漏桶和令牌桶的区别:令牌桶常用于控制并发,无论何时,令牌的总数是固定的,每次调用开始都需要申请,调用结束都需要释放;而漏桶适用于控制QPS,漏桶可以在每秒生成m个令牌,每次调用开始都需要申请,但调用结束不需要释放,不过问题就是如果上一秒的调用没有结束,实际调用会大于当前生成的m个令牌控制的调用量。

RateLimiter

Google 开源工具包 Guava 提供了限流工具类 RateLimiter,该类基于令牌桶算法实现流量限制,使用十分方便,而且十分高效。

首先简单介绍下 RateLimiter 的使用:

public void testAcquire() {
  RateLimiter limiter = RateLimiter.create(1);

  for(int i = 1; i < 10; i = i + 2 ) {
    double waitTime = limiter.acquire(i);
    System.out.println("cutTime=" + System.currentTimeMillis() 
        + " acq:" + i 
        + " waitTime:" + waitTime);
  }
}

输出结果:

cutTime=1535439657427 acq:1 waitTime:0.0
cutTime=1535439658431 acq:3 waitTime:0.997045
cutTime=1535439661429 acq:5 waitTime:2.993028
cutTime=1535439666426 acq:7 waitTime:4.995625
cutTime=1535439673426 acq:9 waitTime:6.999223

首先通过 RateLimiter.create(1); 创建一个限流器,参数代表每秒生成的令牌数,通过 limiter.acquire(i); 来以阻塞的方式获取令牌,当然也可以通过 tryAcquire(int permits, long timeout, TimeUnit unit) 来设置等待超时时间的方式获取令牌,如果超 timeout 为0,则代表非阻塞,获取不到立即返回。

从输出来看,RateLimiter 支持预消费,比如在 acquire(5) 时,等待时间是3秒,是上一个获取令牌时预消费了3个两排,固需要等待 3*1 秒,然后又预消费了5个令牌,以此类推。

RateLimiter 通过限制后面请求的等待时间,来支持一定程度的突发请求(预消费),在使用过程中需要注意这一点,具体实现原理后面再分析。

信号量

操作系统的信号量是个很重要的概念,Java 并发库 的Semaphore 可以很轻松完成信号量控制,Semaphore 可以控制某个资源可被同时访问的个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

信号量的本质是控制某个资源可被同时访问的个数,在一定程度上可以控制某资源的访问频率,但不能精确控制。

public static void main(String[] args) {

  ExecutorService executorService = Executors.newCachedThreadPool();
  // 信号量,只允许 3个线程同时访问
  Semaphore semaphore = new Semaphore(3);
  for (int i=0;i<10;i++){
    final long num = i;
    executorService.submit(new Runnable() {
      @Override
      public void run() {
        try {
          // 获取许可
          semaphore.acquire();
          // 执行
          System.out.println("Accessing: " + num);
          Thread.sleep(new Random().nextInt(5000)); // 模拟随机执行时长
          // 释放
          semaphore.release();
          System.out.println("Release..." + num);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    });
  }
  executorService.shutdown();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值