Guava RateLimter 基础学习

  • 平滑突发限流
  • 平滑预热限流
  • 原理分析--以平滑突发限流为例
  • 缺点
  • 结合Redis实现分布式
    • 思路

平滑突发限流

   public static void main(String[] args) {RateLimiter rateLimiter = RateLimiter.create(5);while (true) {double acquire = rateLimiter.acquire();System.out.println(acquire);}}/**0.00.1987560.194320.199067*/

可见 令牌并不是一次性给的,而是在这一秒中,按照固定的速率分发的,所以每一个请求大概0.2s。不过,RateLimiter有积累的作用,在桶还没有满的情况下,RateLimiter会一直分发,直到桶被装满位置,这时候如果来了请求,只要令牌还没有被分发完,就可以立即获得令牌,所以RateLimiter可以应对突发性流量。

 public static void main(String[] args) throws InterruptedException {RateLimiter rateLimiter = RateLimiter.create(5);Thread.sleep(1000);while (true) {double acquire = rateLimiter.acquire();System.out.println(acquire);}}/**0.00.00.00.00.00.00.1986760.194248*/

RateLimiter还有一个特性,在没有足够令牌发放时,采用滞后处理的方式;比如,现在只有3个令牌,但是现在有一个请求要4个令牌,可以立即响应,先跟RateLimiter借1个令牌。这个请求获取令牌所需等待的时间由下一次请求来承受,也就是代替前一个请求进行等待。

   public static void main(String[] args) throws InterruptedException {RateLimiter rateLimiter = RateLimiter.create(6);Thread.sleep(1000);System.out.println(rateLimiter.acquire(3));System.out.println(rateLimiter.acquire(4)); //令牌不够,但是仍然能立即返回System.out.println(rateLimiter.acquire(1));}/**0.0
0.0
0.163041*/

平滑预热限流

我们先来看一下源码

    //permitsPerSecond请求的令牌个数,warmupPeriod预热的时间,unit预热时间间隔单位public static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit) {Preconditions.checkArgument(warmupPeriod >= 0L, "warmupPeriod must not be negative: %s", new Object[]{warmupPeriod});return create(RateLimiter.SleepingStopwatch.createFromSystemTimer(), permitsPerSecond, warmupPeriod, unit);}

带有预热期的平滑限流,他启动后会有一段预热期,发放令牌的频率和时间呈一个梯度,等到时间过了warmupPeriod,才到达原本设置的频率。这种功能主要适合系统刚启动需要一点时间来“热身”的场景。

        RateLimiter rateLimiter = RateLimiter.create(6, 2, TimeUnit.SECONDS);while (true) {System.out.println(rateLimiter.acquire(2));}/**0.00.888101   0.6601520.439506  上面加起来刚好差不多2s0.328413  热身完毕0.3295040.329148
*/

原理分析–以平滑突发限流为例

我们先从acquire看起

 public double acquire() {return this.acquire(1);}public double acquire(int permits) {// 返回现在需要等待的时间long microsToWait = this.reserve(permits);//睡眠 阻塞this.stopwatch.sleepMicrosUninterruptibly(microsToWait);//返回等待的时间 转换成秒return 1.0D * (double)microsToWait / (double)TimeUnit.SECONDS.toMicros(1L); }final long reserve(int permits) {checkPermits(permits); //检查permits是否合理 >0synchronized(this.mutex()) { //lockreturn this.reserveAndGetWaitLength(permits, this.stopwatch.readMicros()); //返回需要等待的时间//this.stopwatch.readMicros() 现在的时间 }}final long reserveAndGetWaitLength(int permits, long nowMicros) {long momentAvailable = this.reserveEarliestAvailable(permits, nowMicros); //算出距离现在最近的能够获取令牌的时间return Math.max(momentAvailable - nowMicros, 0L);//返回需要等待的时间}

接下来我们来看一下reserveEarliestAvailabe是怎么算出最近能够获取到令牌的时间

final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {// 刷新令牌数,相当于每次acquire的时候才根据时间进行令牌的刷新resync(nowMicros);//nextFreeTicketMicros 下一次请求可以获取令牌的时间 成员属性long returnValue = nextFreeTicketMicros;// 获取当前已有的令牌数和需要获取的目标令牌数进行比较,计算出可以目前即可得到的令牌数。double storedPermitsToSpend = min(requiredPermits, this.storedPermits);// freshPermits是需要预先支付的令牌,也就是目标令牌数减去目前即可得到的令牌数// 因为会突然涌入大量请求,而现有令牌数又不够用,因此会预先支付一定的令牌数double freshPermits = requiredPermits - storedPermitsToSpend;// waitMicros即是产生预先支付令牌的数量时间,则将下次要添加令牌的时间应该计算时间加上watiMicros//stableIntervalMicros 添加令牌的时间间隔//SmoothBuresty的storedPermitsToWaitTime直接返回0,所以watiMicros就是预先支付的令牌所需等待的时间  但是在SmoothWarmingUp中就不一样,用于实现预热缓冲期long waitMicros = storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)+ (long) (freshPermits * stableIntervalMicros);try {// 更新nextFreeTicketMicros,本次预先支付的令牌所需等待的时间让下一次请求来实际等待。this.nextFreeTicketMicros = LongMath.checkedAdd(nextFreeTicketMicros, waitMicros);} catch (ArithmeticException e) {this.nextFreeTicketMicros = Long.MAX_VALUE;}// 更新令牌数,最低数量为0this.storedPermits -= storedPermitsToSpend;// 返回旧的nextFreeTicketMicros数值,无需为预支付的令牌多加等待时间。return returnValue;
}// SmoothBurest
long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {return 0L;
}//更新令牌数
void resync(long nowMicros) {// 当前时间晚于nextFreeTicketMicros,所以刷新令牌和nextFreeTicketMicrosif (nowMicros > nextFreeTicketMicros) {// coolDownIntervalMicros函数获取每几秒生成一个令牌,SmoothWarmingUp和SmoothBuresty的实现不同// SmoothBuresty的coolDownIntervalMicros直接返回stableIntervalMicros// 当前时间减去要更新令牌的时间获取时间间隔,再除以添加令牌时间间隔获取这段时间内要添加的令牌数storedPermits = min(maxPermits,storedPermits+ (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros());nextFreeTicketMicros = nowMicros;}// 如果当前时间早于nextFreeTicketMicros,则获取令牌的线程要一直等待到nextFreeTicketMicros,该线程获取令牌所需// 额外等待的时间由下一次获取的线程来代替等待。
}
//返回生成令牌的时间间隔
double coolDownIntervalMicros() {return stableIntervalMicros;
}

缺点

  • RateLimiter只能运用与单机不能运用与分布式
  • 结合redis实现分布式

结合Redis实现分布式

思路

  • 自己按照这个原理写一个锁,把字段放在redis里面

Guava RateLimter 基础学习相关推荐

  1. 【转】oracle PLSQL基础学习

    [转]oracle PLSQL基础学习 --oracle 练习: /**************************************************PL/SQL编程基础****** ...

  2. python创建对象的格式为_Python入门基础学习(面向对象)

    python基础学习笔记(四) 面向对象的三个基本特征: 封装:把客观事物抽象并封装成对象,即将属性,方法和事件等集合在一个整体内 继承:允许使用现有类的功能并在无须重新改写原来的类情况下,对这些功能 ...

  3. 虚幻引擎虚拟现实开发基础学习教程

    流派:电子学习| MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小解压后:3.93 GB |时长:5h 15m 了 ...

  4. 动画产业基础学习教程 Rad How to Class – Animation Industry Fundamentals

    如何分类--动画产业基础 大小解压后:6.2G 含课程素材 1920X1080 mp4 语言:英语+中英文字幕(根据原英文字幕机译更准确) 信息: 绘画技巧.解剖学.角色设计.透视和整体讲故事--这门 ...

  5. Blender纹理基础学习视频教程 CGCookie – Fundamentals of Texturing in Blender

    Blender纹理基础学习视频教程 CGCookie – Fundamentals of Texturing in Blender Blender纹理基础学习视频教程 CGCookie – Funda ...

  6. ue5新手零基础学习教程 Unreal Engine 5 Beginner Tutorial - UE5 Starter Course

    ue5新手零基础学习教程 Unreal Engine 5 Beginner Tutorial - UE5 Starter Course! 教程大小解压后:4.96G 语言:英语+中英文字幕(机译)时长 ...

  7. 0基础学好python难不难_零基础学习Python难不难?Python有什么优势?

    原标题:零基础学习Python难不难?Python有什么优势? Python是一种计算机程序设计语言.首先,我们普及一下编程语言的基础知识.用任何编程语言来开发程序,都是为了让计算机干活,比如下载一个 ...

  8. 计算机一级ps2019,2019年计算机一级考试PS基础学习点子:PS菜单中英文对照表.docx...

    2019 年计算机一级考试 PS 基础学习点子: PS 菜单中英文对照表 PS菜单中英文对照表 一.File New 2.Open 3.Open As 4.Open Recent Close 6.Sa ...

  9. Java零基础学习难吗

    java编程是入行互联网的小伙伴们大多数的选择,那么对于零基础的小伙伴来说Java零基础学习难吗?如果你是初学者,你可以很好的理解java编程语言.并不困难.如果你的学习能力比较高,那么你对Java的 ...

最新文章

  1. SWPU OnlingJudge 在线评测平台 使用教程
  2. 社会丨中外大学校长:人工智能时代 未来高校教什么
  3. js判断ipad还是安卓_还考虑iPad?荣耀平板V6麒麟985支持5G才3000多元
  4. boost::mpl模块实现range_c相关的测试程序
  5. Android热修复Tinker接入文档
  6. web表格在css中属性,CSS属性之表格(Table)_html/css_WEB-ITnose
  7. 30天C#基础巩固------了解委托,string练习
  8. Java Instrument
  9. 3rd Batch请查收!您的问题解答清单
  10. html请假条源码,请假条(事假) 的例子
  11. java pppoe_PPPoE拨号流程
  12. Memcached的LRU策略
  13. 03-jQuery事件绑定和解绑
  14. Java分布式中文分词组件 - word分词(转自:https://github.com/ysc/word)
  15. homeassistant搭建_梅林搭建home-assistant
  16. 【转】国内超级计算机发展情况简介
  17. 完全图与强连通图的那些坑
  18. 丑数_题目1214:丑数
  19. Roadstar.ai陷罗生门!内斗升级,周光与另两位创始人各执一词
  20. 串口转以太网通信源代码C语言C++编写支持多路转换双向通信支持UDP和TCP客户端 提供

热门文章

  1. 支付宝报错:系统繁忙,请稍后重试(ALIN10070)
  2. ms08-067漏洞的复现及所遇到的问题分析
  3. c语言编写扫雷小游戏下载大全,C语言实现扫雷小游戏
  4. 【UVM】sequence 的启动方式
  5. Doris之sequence列
  6. c语言 static运用,灵活改变生命周期,让你写代码如鱼得水
  7. 【练习篇】SQLZOO(中文版)习题答案_SELECT from world
  8. 浅谈前端安全以及如何防范
  9. ViewPage 实现卡片效果
  10. RoboMaster遥控器配置