Eureka的限流算法类RateLimiter是基于令牌桶算法来实现的,下面看一看令牌桶算法的原理:

对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。如图所示,令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。

源码解读:

package com.lovnx.web;import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;/*** @Class RateLimiter 实现基于令牌桶算法,有两个参数:* * @para  burstSize - 允许作为突发事件进入系统的最大请求数* @para  averageRate - 预期的每秒请求数(新版本也支持使用分钟为单位)* * @author lovnx*/
public class RateLimiter {//限流时间单位private final long rateToMsConversion;//当前可供消费的令牌数量private final AtomicInteger consumedTokens = new AtomicInteger();//上一次填充令牌的时间戳private final AtomicLong lastRefillTime = new AtomicLong(0);//限流时间单位可设置为TimeUnit.SECONDS,已废弃@Deprecatedpublic RateLimiter() {this(TimeUnit.SECONDS);}//限流时间单位可设置为TimeUnit.SECONDS或TimeUnit.MINUTESpublic RateLimiter(TimeUnit averageRateUnit) {switch (averageRateUnit) {case SECONDS:rateToMsConversion = 1000;break;case MINUTES:rateToMsConversion = 60 * 1000;break;default:throw new IllegalArgumentException("TimeUnit of " + averageRateUnit + " is not supported");}}//这个方法默认传的当前系统时间戳public boolean acquire(int burstSize, long averageRate) {return acquire(burstSize, averageRate, System.currentTimeMillis());}public boolean acquire(int burstSize, long averageRate, long currentTimeMillis) {//这里为了避免傻白甜将burstSize和averageRate设为负值而抛出异常if (burstSize <= 0 || averageRate <= 0) {return true;}//填充令牌refillToken(burstSize, averageRate, currentTimeMillis);//消费令牌成功与否return consumeToken(burstSize);}private void refillToken(int burstSize, long averageRate, long currentTimeMillis) {//得到上一次填充令牌的时间戳long refillTime = lastRefillTime.get();//时间间隔timeDelta = 传进来的时间戳currentTimeMillis - 上一次填充令牌的时间戳refillTimelong timeDelta = currentTimeMillis - refillTime;//计算出新的令牌数量newTokens = 时间间隔 * 平均速率 / 限流时间单位long newTokens = timeDelta * averageRate / rateToMsConversion;//如果新的令牌数量大于0个if (newTokens > 0) {//设置新的填充令牌时间戳newRefillTime,如果上一次填充令牌的时间戳==0就取传进来的currentTimeMillis,如果!=0,//就等于上一次填充令牌的时间戳 + 新的令牌数量 * 限流时间单位 / 平均速率long newRefillTime = refillTime == 0? currentTimeMillis: refillTime + newTokens * rateToMsConversion / averageRate;//如果lastRefillTime内存偏移量值==上一次填充令牌的时间戳refillTime,则将lastRefillTime内存值设置为新的填充令牌时间戳newRefillTime//成功时进入条件体放令牌if (lastRefillTime.compareAndSet(refillTime, newRefillTime)) {//放令牌(核心代码)while (true) {//得到当前已消费的令牌数量currentLevelint currentLevel = consumedTokens.get();//获取校正令牌数量adjustedLevel,从当前已消费的令牌数量currentLevel和允许最大请求数burstSize间取小者,以防允许最大请求数burstSize变小//这一步和下一步叫做“流量削峰”int adjustedLevel = Math.min(currentLevel, burstSize);//获取新的令牌数量newLevel,0 与 (校正值 - 计算值)之间取大者int newLevel = (int) Math.max(0, adjustedLevel - newTokens);//如果当前已消费的令牌内存偏移量等于consumedTokens等于currentLevel,则将已消费的令牌量consumedTokens设置为新的令牌数量newLevel//终止放令牌,在已消费偏移量不等于currentLevel时循环计算,直到它们相等if (consumedTokens.compareAndSet(currentLevel, newLevel)) {return;}}}}}//消费令牌,传入突发量private boolean consumeToken(int burstSize) {//取令牌while (true) {//得到当前已消费的令牌数量currentLevelint currentLevel = consumedTokens.get();//如果已消费令牌量大于等于突发量,则不能消费令牌if (currentLevel >= burstSize) {return false;}//消费令牌,已消费令牌量+1if (consumedTokens.compareAndSet(currentLevel, currentLevel + 1)) {return true;}}}//重置令牌桶public void reset() {consumedTokens.set(0);lastRefillTime.set(0);}
}

Eureka的限流算法类RateLimiter源码解读相关推荐

  1. 儒猿秒杀季!微服务限流熔断技术源码剖析与架构设计

    疯狂秒杀季:49元秒杀 原价 299元 的 <微服务限流熔断技术源码剖析与架构设计课> 今天 上午11点,仅 52 套,先到先得! === 课程背景 === 成为一名架构师几乎是每个程序员 ...

  2. 图解Kafka分区副本同步限流机制三部曲(源码原理篇+测试用例 )

  3. SpringMvc 限流之 RateLimiter

    概念 限流 限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务.排队或等待.降级等处理 常用限流算法 常用的限流算法有两种:漏桶算法 ...

  4. Guava RateLimiter算法原理及源码解读

    目录 前言 原理 RateLimiter原理 SmoothBursty 关键属性 关键方法 doSetRate reserveEarliestAvailable SmoothWarmingUp War ...

  5. 【2022修复版】社群扫码进群活码引流完整运营源码/带视频搭建教程

    搭建环境 1.环境Nginx MySQL 5.6 php7.2 php7.2安装扩展fileinfo redis Swoole sg11 服务器需要安装linux的系统, 安装上宝塔,在配置这些环境就 ...

  6. 软件导航页源码+可封装APP/下载软件引流整站源码

    正文: 完整标题: 源码介绍: APP软件应用下载导航网站源码/APP分享下载页引流导航网站源码带后台版 这款源码 安装非常便捷干净,源码只有十几MB 只需要上传源码修改数据库连接信息即可使用. 后台 ...

  7. Feflow 源码解读

    Feflow 源码解读 Feflow(Front-end flow)是腾讯IVWEB团队的前端工程化解决方案,致力于改善多类型项目的开发流程中的规范和非业务相关的问题,可以让开发者将绝大部分精力集中在 ...

  8. spring-session源码解读 sesion

    2019独角兽企业重金招聘Python工程师标准>>> spring-session源码解读 sesion 博客分类: java spring 摘要: session通用策略 Ses ...

  9. Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_2

    文章目录 Pre 源码解读 总体流程 源码分析 细节解析 [初始化对应的集合 & 遍历用户自己手动添加的后置处理器] [调用实现了PriorityOrdered接口的BeanDefinitio ...

最新文章

  1. ICML 2020论文贡献榜排名出炉:Google单挑斯坦福、MIT、伯克利;清华进TOP 20
  2. 【转】C#获取电脑客户端IP地址及当前用户名
  3. QT的QStateMachine类的使用
  4. sqlserver 2008 R2 删除重复数据
  5. P6047-丝之割【斜率优化,dp】
  6. php中对ASCII码的处理ord() 、chr()
  7. mysql5.6开启binlog日志
  8. ffplay for mfc 代码备忘
  9. 图解Python机器学习pdf 中日双语 第1页
  10. 利用Python的PyPDF2库,根据论文标题批量修改pdf的文件名
  11. 鼠标悬停在HTML-TABLE的某一行上 改变这一行的背景颜色
  12. mysql 存储特殊符号_mysql 存储特殊符号
  13. u盘启动怎么修复计算机,计算机黑屏怎么办 如何使用u盘启动制作系统
  14. 高效实现统计分析(按日,月,周)查询功能
  15. Processing——码绘与手绘对比动态篇
  16. ThinkPad笔记本无法调节亮度
  17. 数模新版视频课程第11讲.时间序列分析
  18. 有线耳机真成了“时代的弃儿”?
  19. 算法学习:高精度加法//c++
  20. 解决报错Error: libzip5-tools conflicts with libzip-0.10.1-8.el7.x86_64

热门文章

  1. 机器人是如何实现对话的?
  2. 千峰教学视频(官方)
  3. Ceph集群显示XXX daemons have recently crashed警告
  4. Kafka 集群在马蜂窝大数据平台的优化与应用扩展
  5. C++学习笔记(五)opencv在win下的使用 —参考浅墨opencv3编程入门
  6. 查看bpl 引用的dll_BPL与DLL
  7. 泛型 super和extend
  8. U启动后计算机能看到原系统文件吗,u启动一键急救系统使用
  9. QT5 隐藏系统标题栏,自己编写个性靓丽标题栏
  10. SpringCloud系列(2)---Netfilx-Eureka