前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Google出品的限流术RateLimiter

Google出品的限流术RateLimiter

作者头像
JavaQ
发布2018-04-04 17:17:43
2.1K0
发布2018-04-04 17:17:43
举报
文章被收录于专栏:JavaQJavaQJavaQ

限流

通过对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机。常用的限流算法有令牌桶和和漏桶,而Google开源项目Guava中的RateLimiter使用的就是令牌桶控制算法。

令牌桶算法

有一个固定容量用于存储令牌的桶,按照设定的频率向桶中放入令牌,过程如下图所示。

过程描述如下:

  • 如果设定每秒向桶中放入5个令牌,则将会以每200毫秒的固定速率向桶中放入一个令牌;
  • 桶中最多存放n个令牌,如果桶满了,则新放入的令牌将会被丢弃;
  • 当一个m字节的数据包到达时,将会使用m个令牌,然后将该数据包发出;
  • 如果桶中可用令牌数小于k,则该数据包将需要等待或丢弃。

RateLimiter

RateLimiter实现的令牌桶算法,不仅可以应对正常流量的限速,而且可以处理突发暴增的请求,实现平滑限流。RateLimiter方法摘要如下。

修饰符和类型

方法和描述

double

acquire()从RateLimiter获取一个令牌,该方法会被阻塞直到获取到令牌

double

acquire(int permits)从RateLimiter获取指定数量令牌,该方法会被阻塞直到获取到指定数量令牌

static RateLimiter

create(double permitsPerSecond)根据指定的吞吐量(permitsPerSecond)创建RateLimiter,permitsPerSecond指每秒可执行的数量,也指每秒放入的令牌数

static RateLimiter

create(double permitsPerSecond, long warmupPeriod, TimeUnit unit)根据指定的吞吐量(permitsPerSecond)和预热期(warmupPeriod)来创建RateLimiter,permitsPerSecond指每秒可执行的数量,也指每秒放入的令牌数 ,在这段预热时间内,RateLimiter每秒加入的令牌数会平稳地增长直到预热期结束时达到其最大速率。

double

getRate()返回RateLimiter设置的固定频率,该频率指每秒加入的令牌数

void

setRate(double permitsPerSecond)设置RateLimite的固定频率

boolean

tryAcquire()尝试立即获取令牌,获取不到返回false,获取到返回true

boolean

tryAcquire(int permits)尝试立即获取permits个令牌,获取不到返回false,获取到返回true

boolean

tryAcquire(int permits, long timeout, TimeUnit unit)在以unit为时间单位的timeout时间范围内,尝试获取permits个令牌,获取不到返回false,获取到返回true

boolean

tryAcquire(long timeout, TimeUnit unit)在以unit为时间单位的timeout时间范围内,尝试获取1个令牌,获取不到返回false,获取到返回true

应用

场景:向第三方服务发送多笔查询请求,如果是单线程发送请求,效率很慢;如果使用多线程发送,第三方服务处理能力有限,直接返回失败。

方案:使用RateLimiter限制发送请求的频率,假设第三方服务每秒可处理5笔请求,示例代码如下。

List<String> queryNos = newArrayList("1", "2", "3", "4", "5", "6", "7"); RateLimiter limiter = RateLimiter.create(5); ExecutorService executorService = Executors.newFixedThreadPool(5); for (final String queryNo : queryNos) { limiter.acquire(); executorService.submit(new Runnable() { public void run() { //...发送请求 System.out.println(queryNo + ":" + Calendar.getInstance().getTimeInMillis()); } }); }

结果输出如下:

1:1499333845323

2:1499333845505

3:1499333845704

4:1499333845904

5:1499333846105

6:1499333846304

7:1499333846504

可以看到每个请求间隔差不多200毫秒,实现了限流。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-07-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JavaQ 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档