RateLimiter是Guava的concurrent包下的一个用于限制访问频率的类.

限流算法

常用的更平滑的限流算法有两种:漏桶算法和令牌桶算法.

很多传统的服务提供商如华为中兴都有类似的专利,参考: http://www.google.com/patents/CN1536815A?cl=zh

漏桶算法

漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率.示意图如下:

可见这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate),伪代码如下:

double rate; // leak rate in calls/s
double burst; // bucket size in calls
long refreshTime; // time for last water refresh
double water; // water count at refreshTime
refreshWater() {
long now = getTimeOfDay();
//水随着时间流逝,不断流走,最多就流干到0.
water = max(0, water- (now - refreshTime)*rate);
refreshTime = now;
}
bool permissionGranted() {
refreshWater();
if (water < burst) { // 水桶还没满,继续加1
water ++;
return true;
} else {
return false;
}
}

因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发(burst)到端口速率.因此,漏桶算法对于存在突发特性的流量来说缺乏效率.

令牌桶算法

令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解.随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.

令牌桶的另外一个好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.

RateLimiter简介

Google开源工具包Guava提供了限流工具类RateLimiter,该类基于令牌桶算法(Token Bucket)来完成限流,非常易于使用.RateLimiter经常用于限制对一些物理资源或者逻辑资源的访问速率.它支持两种获取permits接口,一种是如果拿不到立刻返回false,一种会阻塞等待一段时间看能不能拿到.

RateLimiter和Java中的信号量(java.util.concurrent.Semaphore)类似,Semaphore通常用于限制并发量.

源码注释中的一个例子,比如我们有很多任务需要执行,但是我们不希望每秒超过两个任务执行,那么我们就可以使用RateLimiter:

final RateLimiter rateLimiter = RateLimiter.create(2.0);
void submitTasks(List<Runnable> tasks, Executor executor) {
for (Runnable task : tasks) {
rateLimiter.acquire(); // may wait
executor.execute(task);
}
}

另外一个例子,假如我们会产生一个数据流,然后我们想以每秒5kb的速度发送出去.我们可以每获取一个令牌(permit)就发送一个byte的数据,这样我们就可以通过一个每秒5000个令牌的RateLimiter来实现:

final RateLimiter rateLimiter = RateLimiter.create(5000.0);
void submitPacket(byte[] packet) {
rateLimiter.acquire(packet.length);
networkService.send(packet);
}

另外,我们也可以使用非阻塞的形式达到降级运行的目的,即使用非阻塞的tryAcquire()方法:

if(limiter.tryAcquire()) { //未请求到limiter则立即返回false
doSomething();
}else{
doSomethingElse();
}

RateLimiter主要接口

RateLimiter其实是一个abstract类,但是它提供了几个static方法用于创建RateLimiter:

/**
* 创建一个稳定输出令牌的RateLimiter,保证了平均每秒不超过permitsPerSecond个请求
* 当请求到来的速度超过了permitsPerSecond,保证每秒只处理permitsPerSecond个请求
* 当这个RateLimiter使用不足(即请求到来速度小于permitsPerSecond),会囤积最多permitsPerSecond个请求
*/
public static RateLimiter create(double permitsPerSecond);
/**
* 创建一个稳定输出令牌的RateLimiter,保证了平均每秒不超过permitsPerSecond个请求
* 还包含一个热身期(warmup period),热身期内,RateLimiter会平滑的将其释放令牌的速率加大,直到起达到最大速率
* 同样,如果RateLimiter在热身期没有足够的请求(unused),则起速率会逐渐降低到冷却状态
*
* 设计这个的意图是为了满足那种资源提供方需要热身时间,而不是每次访问都能提供稳定速率的服务的情况(比如带缓存服务,需要定期刷新缓存的)
* 参数warmupPeriod和unit决定了其从冷却状态到达最大速率的时间
*/
public static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit);

提供了两个获取令牌的方法,不带参数表示获取一个令牌.如果没有令牌则一直等待,返回等待的时间(单位为秒),没有被限流则直接返回0.0:

public double acquire();
public double acquire(int permits);

尝试获取令牌,分为待超时时间和不带超时时间两种:

public boolean tryAcquire();
//尝试获取一个令牌,立即返回
public boolean tryAcquire(int permits);
public boolean tryAcquire(long timeout, TimeUnit unit);
//尝试获取permits个令牌,带超时时间
public boolean tryAcquire(int permits, long timeout, TimeUnit unit);

RateLimiter的更多相关文章

  1. guava学习--ratelimiter

    RateLimiter类似于JDK的信号量Semphore,他用来限制对资源并发访问的线程数. RateLimiter limiter = RateLimiter.create(4.0); //每秒不 ...

  2. Guava并发:ListenableFuture与RateLimiter示例

    ListenableFuture顾名思义就是可以监听的Future,它是对java原生Future的扩展增强 RateLimiter类似于JDK的信号量Semphore,他用来限制对资源并发访问的线程 ...

  3. 分布式环境下限流方案的实现redis RateLimiter Guava,Token Bucket, Leaky Bucket

    业务背景介绍 对于web应用的限流,光看标题,似乎过于抽象,难以理解,那我们还是以具体的某一个应用场景来引入这个话题吧. 在日常生活中,我们肯定收到过不少不少这样的短信,“双11约吗?,千款….”,“ ...

  4. Guava官方文档-RateLimiter类

    转载自并发编程网 – ifeve.com RateLimiter 从概念上来讲,速率限制器会在可配置的速率下分配许可证.如果必要的话,每个acquire() 会阻塞当前线程直到许可证可用后获取该许可证 ...

  5. 超详细的Guava RateLimiter限流原理解析

    超详细的Guava RateLimiter限流原理解析  mp.weixin.qq.com 点击上方“方志朋”,选择“置顶或者星标” 你的关注意义重大! 限流是保护高并发系统的三把利器之一,另外两个是 ...

  6. 业务限流场景简单实现方案:RateLimiter

    前因:因为本系统中,有大数据高并发的场景.在向下游系统发送请求的时候,需要限流.否则会造成下游系统的堵塞. 实现方案1: Thread.sleep(ms). 优点:简单粗暴,一行代码搞定 缺点:有点l ...

  7. 流量控制与RateLimiter

    一背景 如何提高系统的稳定性,简单来说除了加机器外就是服务降级.限流.加机器就是常说的分布式,从整个架构的稳定性角度看,一般SOA每个接口的所能提供的单位时间服务能力是有上限.假如超过服务能力,一般会 ...

  8. 【Guava】使用Guava的RateLimiter做限流

    一.常见的限流算法 目前常用的限流算法有两个:漏桶算法和令牌桶算法. 1.漏桶算法 漏桶算法的原理比较简单,请求进入到漏桶中,漏桶以一定的速率漏水.当请求过多时,水直接溢出.可以看出,漏桶算法可以强制 ...

  9. 使用Guava的RateLimiter完成简单的大流量限流

    限流的一般思路: 1.随机丢弃一定规则的用户(迅速过滤掉90%的用户): 2.MQ削峰(比如设一个MQ可以容纳的最大消息量,达到这个量后MQ给予reject): 3.业务逻辑层使用RateLimite ...

  10. Guava的RateLimiter在单机限流中的正确用法

    错误使用 在实现限流时,网上的各种文章基本都会提到Guava的RateLimiter,用于实现单机的限流,并给出类似的代码: public void method() { RateLimiter ra ...

随机推荐

  1. sqlite读写

    #coding=utf-8 import sqlite3 import os #创建数据库和游标 if os.path.exists(' test.db'): conn=sqlite3.connect ...

  2. django模型查询操作

    一旦创建好了数据模型,Django就会自动为我们提供一个数据库抽象API,允许创建.检索.更新和删除对象操作 下面的示例都是通过下面参考模型来对模型字段进行操作说明: from django.db i ...

  3. JedisConnectionException: java.net.ConnectException: Connection refused

    出现问题 我遇到的一个问题,在连接redis的时候出现了错误!错误如下: JedisConnectionException: java.net.ConnectException: Connection ...

  4. C# Socket异步实现消息发送--附带源码

    前言 看了一百遍,不如动手写一遍. Socket这块使用不是特别熟悉,之前实现是公司有对应源码改改能用. 但是不理解实现的过程和步骤,然后最近有时间自己写个demo实现看看,熟悉熟悉Socket. 网 ...

  5. Swift map filter reduce 使用指南

    转载:https://useyourloaf.com/blog/swift-guide-to-map-filter-reduce/ Using map, filter or reduce to ope ...

  6. 使用Plant Simulation连接SQL Server

    1. 在管理类库中添加ODBC. 2. 在控制面板->管理工具中设置ODBC,添加SQL Server服务. 3. 在plant simulation中将信息流中的ODBC添加到Frame中. ...

  7. BZOJ.4514.[SDOI2016]数字配对(费用流SPFA 二分图)

    BZOJ 洛谷 \(Solution\) 很显然的建二分图后跑最大费用流,但有个问题是一个数是只能用一次的,这样二分图两部分都有这个数. 那么就用两倍的.如果\(i\)可以向\(j'\)连边,\(j\ ...

  8. 2016 Multi-University Training Contest 6 题解

    我只能说: A Boring Question 下面公式重复了一行 \[ \sum\_{0\leq k\_{1},k\_{2},\cdots k\_{m}\leq n}\prod\_{1\leq j& ...

  9. CCCC 成都信息工程大学游记

    晚上刷智障25人本,刷到深夜四点,然后迷迷糊糊8点钟起床上车睡觉,然后就到了信息工程大学. 然后开始抢衣服,抢完衣服就开始拍照. 对了,这个学校看了下地图,好小呀,不过妹子好多呀. 然后就被老师带进机 ...

  10. [原创]浅谈H5页面性能测试

    [原创]浅谈H5页面性能测试 H5页面我想各位都不陌生,随着移动互联网兴起,不管是App,还是H5都火起来了,最突出的2个表现是ios/android/前端等工程师薪水大涨,尤其是资深前端工程师40W ...