guava限流器RateLimiter原理及源码分析

来源:https://www.cnblogs.com/zhandouBlog/p/11743660.html

前言

RateLimiter是基于令牌桶算法实现的一个多线程限流器,它可以将请求均匀的进行处理,当然他并不是一个分布式限流器,只是对单机进行限流。它可以应用在定时拉取接口数据,

预防单机过大流量使用。

原理

首先先讲一下令牌桶的原理,每隔一段时间生产一个令牌放入桶里,请求在执行时需要拿到令牌才可以执行,如果拿不到令牌将等待令牌产生,一个生产者,多个消费者。

但是这样的令牌桶有一个问题,如果CPU负载过高,生产令牌的线程没有获取到时间片生产令牌,那么限制的流量将会比设定值更低。

可能是出于这个原因,guava并没有这样做,而是一个惰性生产令牌,每次请求令牌时,通过当前时间和下次产生令牌时间的差值计算出现在有多少个令牌,如果当前时间比发放时间大,会获得令牌,并且会生成令牌存储。如果令牌不够,则让线程sleep,并且将下次令牌产生时间更新成当前时间+sleep时间

sleep,并且将下次发放令牌的时间,设置成当前时间+线程sleep的时间。这样说,可能不是很清楚,看图。

 这样做的好处是什么,如果获取令牌的线程抢不到cpu,只是这个线程的执行时间会晚,其他线程不会受到影响。

源码阅读

public static void main(String[] args) {RateLimiter rateLimiter = RateLimiter.create(10);while (true) {long start = System.currentTimeMillis();rateLimiter.acquire();System.out.println(System.currentTimeMillis() - start);}}  

 运行可以发现,上面的代码除了第一次输出的是0或者1,其他都接近100。下面先看一下RateLimiter.create做了哪些事情

static RateLimiter create(double permitsPerSecond, SleepingStopwatch stopwatch) {//创建对象,并且赋值,permitsPerSecond这个是我们设置的qps,stopwatch这个相当于一个计时器,记录相对时间,类似于我上面图中的10ms,100ms等,下面传入的1.0就是一秒的意思,设置上速率就是一秒多少次RateLimiter rateLimiter = new SmoothBursty(stopwatch, 1.0);rateLimiter.setRate(permitsPerSecond);return rateLimiter;}
看一下setRate
public final void setRate(double permitsPerSecond) {checkArgument(permitsPerSecond > 0.0 && !Double.isNaN(permitsPerSecond), "rate must be positive");//从名字就可以看出这是一个互斥锁,这个互斥锁采用了double check懒汉单例模式生成,synchronized (mutex()) {doSetRate(permitsPerSecond, stopwatch.readMicros());}}

下面看一下doSetRate,真正开始设置速率了

final void doSetRate(double permitsPerSecond, long nowMicros) {//这个方法非常重要里面是nextFreeTicketMicros和storedPermits的设置,在生成对象的时候没有用,获取令牌时再讲resync(nowMicros);//这个就是令牌生成间隔,微秒表示double stableIntervalMicros = SECONDS.toMicros(1L) / permitsPerSecond;this.stableIntervalMicros = stableIntervalMicros;这里又有一个doSetRatedoSetRate(permitsPerSecond, stableIntervalMicros);}void doSetRate(double permitsPerSecond, double stableIntervalMicros) {double oldMaxPermits = this.maxPermits;//设置最大令牌maxPermits = maxBurstSeconds * permitsPerSecond;//设置存储令牌if (oldMaxPermits == Double.POSITIVE_INFINITY) {storedPermits = maxPermits;} else {storedPermits =(oldMaxPermits == 0.0)? 0.0 // initial state: storedPermits * maxPermits / oldMaxPermits;}

到了这里整个创建过程就结束了,基本上就是一些设置,创建了锁,设置了生成令牌的间隔时间等等,下面看一下获取令牌的方法。

//获取一个令牌
public double acquire() {return acquire(1);}public double acquire(int permits) {//reserve返回等待时间,内部进行了令牌的获取long microsToWait = reserve(permits);stopwatch.sleepMicrosUninterruptibly(microsToWait);return 1.0 * microsToWait / SECONDS.toMicros(1L);}final long reserve(int permits) {checkPermits(permits);//创建对象时生成的锁synchronized (mutex()) {//stopwatch.readMicros()拿到当前的时间,预订return reserveAndGetWaitLength(permits, stopwatch.readMicros());}}final long reserveAndGetWaitLength(int permits, long nowMicros) {//将数据透传,拿到最早可预订的时间,如果预订时间在未来时间,返回一个大于0的值为等待时间long momentAvailable = reserveEarliestAvailable(permits, nowMicros);return max(momentAvailable - nowMicros, 0);}

下面的代码就是我图中的实现

final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {//这个方法很重要先看下面这个方法的讲解,在从这里往下看resync(nowMicros);//返回下次发放令牌时间,如果这个时间大于当前时间,在调用的上层会sleeplong returnValue = nextFreeTicketMicros;//拿到此次花费的令牌double storedPermitsToSpend = min(requiredPermits, this.storedPermits);// 如果令牌不够,这里就会大于0,下面就会得出一个等待时间double freshPermits = requiredPermits - storedPermitsToSpend;long waitMicros =storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)+ (long) (freshPermits * stableIntervalMicros);//将下次发放令牌的时间加上等待时间this.nextFreeTicketMicros = LongMath.saturatedAdd(nextFreeTicketMicros, waitMicros);this.storedPermits -= storedPermitsToSpend;return returnValue;}void resync(long nowMicros) {if (nowMicros > nextFreeTicketMicros) {//当前时间大于下次令牌发放时间,新的令牌为当前时间减去下次发放令牌时间除以生成令牌的时间间隔double newPermits = (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros();//不能超过最大令牌数storedPermits = min(maxPermits, storedPermits + newPermits);//更新下次发放令牌时间为当前时间nextFreeTicketMicros = nowMicros;}}

总结

RateLimiter的原理用语言描述,很容易把人绕晕,上面的图其实是最好的总结,懂得原理才能更好的使用,在多种限流器中选择合适的限流器。了解源码,能更进一步的掌握原理,并且从源码中可以学到设计思路和

一些设计模式的应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/497396.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

185页深度报告 扒一扒AI金融的老底【附下载】

来源:智东西概要:2016年,中国爆出8家独角兽,总估值964亿美元位冠全球;2017年,毕马威全球百佳金融科技企业前三甲,蚂蚁金服、众安保险、趣店,皆来自中国;过往两年&#xf…

夹娃娃动画Android,手机模拟抓娃娃

手机模拟抓娃娃让你通过手机足不出户也能感受娃娃机的乐趣,萌趣的卡通形象,清新治愈的设计风格,简单上手的玩法,赶快加入进来冲击最高分吧,点击下载手机模拟抓娃娃开始你的挑战!手机模拟抓娃娃介绍手机模拟抓娃娃游戏是一款模拟进行的真人在线抓娃娃的掌上控制的休闲…

android友盟错误日志,Taro(React-native)集成友盟错误日志分析U-App移动统计

1、先去友盟官网注册应用,获取到appkey,友盟移动统计分析U-App,这个步骤就不贴出来了,需要注意的是ios和Android 不能使用同一个appkey,需要分别创建两个应用,应用名称可以在后面加上平台名称,例…

2018年中国新零售市场研究报告——概念、模式与案例【附下载】

来源:亿欧概要:“新零售” 之“新”在于顺势下的“变化”,不应该局限于“阿里巴巴的新零售”。报告尝试从一个更宽广的视角,对当前零售业变化的背景和各种驱动因素进行分析,总结当下时间段零售行业参与者的新动作&…

[导入]ASP.NET 配置节架构

ASP.NET 配置节架构文章来源:http://blog.csdn.net/21aspnet/archive/2004/11/04/167417.aspx转载于:https://www.cnblogs.com/zhaoxiaoyang2/archive/2004/11/05/816261.html

重构--思维导图

#原图 System.out.println("https://www.processon.com/view/60fa8c441e085366ea4c2b9e?fromnew1");

谷歌Jeff Dean团队提出利用深度学习对「电子健康记录」数据进行分析,可提高医疗诊断预测的准确性

原文来源:arXiv作者:Alvin Rajkomar、Eyal Oren、Kai Chen、Andrew M. Dai、Nissan Hajaj、Peter J. Liu、Xiaobing Liu, Mimi Sun、Patrik Sundberg、Hector Yee、Kun Zhang、Yi Zhang、Gavin E. Duggan、Gerardo Flores、Michaela Hardt、Jamie Irvine…

android卫星菜单中间,Android卫星菜单:android-satellite-menu

android-satellite-menu实现点击主按钮,会弹出多个围绕着主按钮排列的子按钮,从而形成一个卫星弹出式菜单。子按钮弹出和消失的动画效果都很棒。这种弹出式菜单按钮应用在Path2.0中。用法在你的view xml中添加组件定义,如下示例:x…

NLP顶级专家Dan Roth :自然语言处理领域近期的任务和主要应用

来源:AI科技大本营概要:1月28日消息,《麻省理工科技评论》新兴科技峰会EmTech China在北京召开,营长也受邀参加,会上有多位人工智能领域的重磅大佬出没,Dan Roth 就是其中一位。1月28日消息,《麻…

【重点!!!】【单调栈】84.柱状图中最大矩形

题目 法1&#xff1a;单调栈[原版] O(N)O(N) 必须掌握算法&#xff01;&#xff01;&#xff01; class Solution {public int largestRectangleArea(int[] heights) {int n heights.length, res 0;int[] leftMin new int[n], rightMin new int[n];Stack<Integer>…

android support library github,Android Support Library 之 夜间模式

原标题&#xff1a;Android Support Library 之 夜间模式前言夜间模式实现方式&#xff1a;1、通过切换theme来实现夜间模式。优点&#xff1a;可以匹配多套主题&#xff0c;并不局限于黑白模式缺点&#xff1a;需要大量定义主题详见博客&#xff1a;http://wuxiaolong.me/2015…

类脑信息处理研究取得进展

来源&#xff1a;AAAI2018概要&#xff1a;近期&#xff0c;中国科学院自动化研究所类脑智能研究中心类脑信息处理&#xff08;BRAVE&#xff09;研究组&#xff0c;在研究员张兆翔的带领下&#xff0c;在借鉴生物神经结构、认知机制与学习特性的神经网络建模与类人学习研究中取…

今天下午爽了一把!

呵呵&#xff0c;很久没这么爽爽地看电影了&#xff0c;一个下午居然连续看了三部电影&#xff01;看到人不想看为止&#xff0c;实在是很过瘾的一个下午啊&#xff01;只是是翘课看的电影&#xff0c;感觉有点不太好&#xff0c;最近真是越来越堕落了。看来要好好克制一下自己…

展望:共融机器人的基础理论与关键技术

来源&#xff1a;《国家科学评论》概要&#xff1a;自1959年工业机器人诞生以来&#xff0c;机器人在机械制造、国防安全、健康服务、科考与医疗等方面发挥出越来越重要的作用。自1959年工业机器人诞生以来&#xff0c;机器人在机械制造、国防安全、健康服务、科考与医疗等方面…

哈萨比斯导师:人工智能媲美人类或需两百年,神经学是条出路

来源&#xff1a;澎湃新闻概要&#xff1a;从围棋到智能驾驶&#xff0c;深度学习缔造了眼下这一波人工智能热潮。在深度学习最热的两大关键词“AlphaGo”和“自动驾驶”&#xff0c;托马索波吉奥&#xff08;Tomaso Poggio&#xff09;都有声名卓著的学生&#xff0c;分别是De…

独家对话英伟达首席科学家:解码AI芯片战局

来源&#xff1a;智东西概要&#xff1a;独家对话Bill Dally博士&#xff0c;深度解读四大AI热点话题。从2017年1月底以来&#xff0c;英伟达的股价又从108美元一路飙升至240多美元&#xff0c;翻了一倍有多。而英伟达股价一飞冲天的背后&#xff0c;正是人工智能技术不断兴盛崛…

[翻译]2005年软件业界推出新产品非官方计划

虽然预测未来的最好方法就是发明(The best way to predict the future is to invent it. -- A. Kay)&#xff0c;但是对于我等现在还没开始发明或者还没有能力发明的人来说&#xff0c;不妨还是看看2005年会软件业界会推出点什么软件&#xff0c;想象一下程序员的生活会不会在2…

Replace Method with Method Object(以函数对象取代函数)

在一个大型函数中&#xff0c;由于局部变量的使用导致无法采用Extract Method class Order...double price() {double primaryBasePrice;double secondaryBasePrice;double teriaryBasePrice;// long computation.....} } 重构&#xff1a;将这个函数放进一个单独对象中&…

2018-2020年中国服务机器人行业深度研究报告

来源&#xff1a;机器人大讲堂概要&#xff1a;目前世界上至少有48个国家在发展机器人&#xff0c;其中25个国家已涉足服务机器人开发。一、报告编写背景和特点北京立德融创智能机器人技术研究院&#xff08;简称“立德研究院”&#xff09;通过对各机器人项目的实施以及自身发…

密歇根大学联合谷歌大脑提出,通过「推断语义布局」实现「文本到图像合成」

原文来源&#xff1a;arXiv作者&#xff1a;Seunghoon Hong、Dingdong Yang、Jongwook Choi、Honglak Lee「雷克世界」编译&#xff1a;嗯~阿童木呀我们通过推断语义布局&#xff08;semantic layout&#xff09;提出了一种新的文本到图像合成&#xff08;text-to-image synthe…