工作中对外提供的API 接口设计都要考虑限流,如果不考虑限流,会成系统的连锁反应,轻者响应缓慢,重者系统宕机,整个业务线崩溃,如何应对这种情况呢,我们可以对请求进行引流或者直接拒绝等操作,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机。

在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流

缓存:缓存的目的是提升系统访问速度和增大系统处理容量
降级:降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行
限流:限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理

限流算法

常用的限流算法有令牌桶和和漏桶,而Google开源项目Guava中的RateLimiter使用的就是令牌桶控制算法。

漏桶算法

把请求比作是水,水来了都先放进桶里,并以限定的速度出水,当水来得过猛而出水不够快时就会导致水直接溢出,即拒绝服务。

漏斗有一个进水口 和 一个出水口,出水口以一定速率出水,并且有一个最大出水速率:

在漏斗中没有水的时候,

  • 如果进水速率小于等于最大出水速率,那么,出水速率等于进水速率,此时,不会积水
  • 如果进水速率大于最大出水速率,那么,漏斗以最大速率出水,此时,多余的水会积在漏斗中

在漏斗中有水的时候

  • 出水口以最大速率出水
  • 如果漏斗未满,且有进水的话,那么这些水会积在漏斗中
  • 如果漏斗已满,且有进水的话,那么这些水会溢出到漏斗之外

令牌桶算法

对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。

令牌桶算法的原理是系统以恒定的速率产生令牌,然后把令牌放到令牌桶中,令牌桶有一个容量,当令牌桶满了的时候,再向其中放令牌,那么多余的令牌会被丢弃;当想要处理一个请求的时候,需要从令牌桶中取出一个令牌,如果此时令牌桶中没有令牌,那么则拒绝该请求。

RateLimiter 用法

https://github.com/google/guava

添加依赖

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>26.0-jre</version><!-- or, for Android: --><version>26.0-android</version>
</dependency>
public class Test {public static void main(String[] args) {ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(100));// 指定每秒放1个令牌RateLimiter limiter = RateLimiter.create(1);for (int i = 1; i < 50; i++) {// 请求RateLimiter, 超过permits会被阻塞//acquire(int permits)函数主要用于获取permits个令牌,并计算需要等待多长时间,进而挂起等待,并将该值返回Double acquire = null;if (i == 1) {acquire = limiter.acquire(1);} else if (i == 2) {acquire = limiter.acquire(10);} else if (i == 3) {acquire = limiter.acquire(2);} else if (i == 4) {acquire = limiter.acquire(20);} else {acquire = limiter.acquire(2);}executorService.submit(new Task("获取令牌成功,获取耗:" + acquire + " 第 " + i + " 个任务执行"));}}
}
class Task implements Runnable {String str;public Task(String str) {this.str = str;}@Overridepublic void run() {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");System.out.println(sdf.format(new Date()) + " | " + Thread.currentThread().getName() + str);}
}

响应

2018-08-11 00:26:22.953 | pool-1-thread-1获取令牌成功,获取耗:0.0 第 1 个任务执行
2018-08-11 00:26:23.923 | pool-1-thread-2获取令牌成功,获取耗:0.98925 第 2 个任务执行
2018-08-11 00:26:33.920 | pool-1-thread-3获取令牌成功,获取耗:9.996993 第 3 个任务执行
2018-08-11 00:26:35.920 | pool-1-thread-4获取令牌成功,获取耗:1.999051 第 4 个任务执行
2018-08-11 00:26:55.920 | pool-1-thread-5获取令牌成功,获取耗:19.999726 第 5 个任务执行
2018-08-11 00:26:57.920 | pool-1-thread-6获取令牌成功,获取耗:1.999139 第 6 个任务执行
2018-08-11 00:26:59.920 | pool-1-thread-7获取令牌成功,获取耗:1.999806 第 7 个任务执行
2018-08-11 00:27:01.919 | pool-1-thread-8获取令牌成功,获取耗:1.999433 第 8 个任务执行

acquire函数主要用于获取permits个令牌,并计算需要等待多长时间,进而挂起等待,并将该值返回

一个RateLimiter主要定义了发放permits的速率。如果没有额外的配置,permits将以固定的速度分配,单位是每秒多少permits。默认情况下,Permits将会被稳定的平缓的发放。

预消费能力

从输出结果可以看出,指定每秒放1个令牌,RateLimiter具有预消费的能力:

acquire 1 时,并没有任何等待 0.0 秒 直接预消费了1个令牌
acquire 10时,由于之前预消费了 1 个令牌,故而等待了1秒,之后又预消费了10个令牌
acquire 2 时,由于之前预消费了 10 个令牌,故而等待了10秒,之后又预消费了2个令牌
acquire 20 时,由于之前预消费了 2 个令牌,故而等待了2秒,之后又预消费了20个令牌
acquire 2 时,由于之前预消费了 20 个令牌,故而等待了20秒,之后又预消费了2个令牌
acquire 2 时,由于之前预消费了 2 个令牌,故而等待了2秒,之后又预消费了2个令牌
acquire 2 时 …

通俗的讲「前人_挖坑_后人跳」,也就说上一次请求获取的permit数越多,那么下一次再获取授权时更待的时候会更长,反之,如果上一次获取的少,那么时间向后推移的就少,下一次获得许可的时间更短。可见,都是有代价的。正所谓:要浪漫就要付出代价。马上就七夕了,浪漫的代价可能要花钱啊,单身狗们。

令牌桶算法VS漏桶算法

漏桶

漏桶的出水速度是恒定的,那么意味着如果瞬时大流量的话,将有大部分请求被丢弃掉(也就是所谓的溢出)。

令牌桶

生成令牌的速度是恒定的,而请求去拿令牌是没有速度限制的。这意味,面对瞬时大流量,该算法可以在短时间内请求拿到大量令牌,而且拿令牌的过程并不是消耗很大的事情。

最后

不论是对于令牌桶拿不到令牌被拒绝,还是漏桶的水满了溢出,都是为了保证大部分流量的正常使用,而牺牲掉了少部分流量,这是合理的,如果因为极少部分流量需要保证的话,那么就可能导致系统达到极限而挂掉,得不偿失。

本文讲的单机的限流,是JVM级别的的限流,所有的令牌生成都是在内存中,在分布式环境下不能直接这么用,可用使redis限流。

接口限流算法:漏桶算法令牌桶算法相关推荐

  1. 信号量与令牌桶_限流的4种方式令牌桶实战

    限流的4种方式 正文 限流 限流是对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机.常用的限流算法有令牌桶和和漏桶,而Google开源项目Guava ...

  2. 什么是限流?为什么会限流呢?常见的限流算法【固定窗口限流、滑动窗口限流、漏桶限流、令牌桶限流】是什么呢?

    什么是限流?为什么会限流呢?常见的限流算法[固定窗口限流.滑动窗口限流.漏桶限流.令牌桶限流]是什么呢? 什么是限流? 为什么会限流? 1. 固定窗口限流算法 1.1 什么是固定窗口限流算法 1.2 ...

  3. 接口限流算法:漏桶算法amp;令牌桶算法

    转载自 接口限流算法:漏桶算法&令牌桶算法 背景 每一个对外提供的API接口都是需要做流量控制的,不然会导致系统直接崩溃.很简单的例子,和保险丝的原理一样,如果用电符合超载就会烧断保险丝断掉电 ...

  4. 高并发策略之限流:计数器、漏桶、令牌桶 三大算法的原理与实战(史上最全)

    导读 网站高可用指的就是:在绝大多的时间里,网站一直处于可以对外提供服务的正常状态. 一般以"年"为单位来统计,"9"的个数越多,代表一年中允许的不可用时间就越 ...

  5. 令牌桶算法和漏桶算法python_限流之漏桶算法与令牌桶算法

    在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流 缓存:缓存的目的是提升系统访问速度和增大系统处理容量 降级:降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降 ...

  6. 带你快速了解:限流中的漏桶和令牌桶算法

    在前文 <限流熔断是什么,怎么做,不做行不行?>中针对 "限流" 动作,有提到流量控制其内部对应着两种常用的限流算法. 其分别对应漏桶算法和令牌桶算法.因此会有的读者会 ...

  7. 使用令牌桶算法解决调用第三方接口限流问题

    我们在调用第三方接口时常常会碰到接口限流问题,为了解决这一问题,大家想出了许多方法.我这里介绍一下我的方法,第三方接口限流一般是基于令牌桶算法的,那么我们可以以彼之道还治彼身,使用令牌桶算法实现我方调 ...

  8. 用令牌桶算法完成API接口限流

    这是张富涛的第15篇原创 用令牌桶算法完成API接口限流 本文介绍了"令牌桶算法",和使用lua+redis实现基于令牌桶算法的限流. 1. 限流需求的产生背景 软件开发时偶尔会面 ...

  9. 【面试大全-高并发】-限流策略有哪些,滑动窗口算法和令牌桶区别,使用场景

    参考思路:限流算法常用的几种实现方式有如下四种:计数器.滑动窗口.漏桶和令牌桶: ● 计数器: ○ 思想:在固定时间窗口内对请求进行计数,与阀值进行比较判断是否需要限流,一旦到了时间临界点,将计数器清 ...

最新文章

  1. AndroidStudio3.0无法打开Android Device Monitor的解决办法(An error has occurred on Android Device Monitor)...
  2. 15、Cocos2dx 3.0游戏开发找小三之Sprite:每一个精灵都是上辈子折翼的天使
  3. 【随机共振】基于随机共振的高频弱信号检测的MATLAB仿真
  4. dom4j Java解析xml应用
  5. MTK 驱动开发(43)---GPS问题分类--MTK ALPS GPS的特殊知识
  6. [渝粤教育] 西南科技大学 高速铁路线路与车站 在线考试复习资料
  7. 简单的汉字和十六进制转换
  8. 安装oracle创建的数据库实例,oracle创建数据库实例
  9. 高质量C/C++编程指南
  10. java下载文件excel格式错乱,excel表格数据错乱如何修复-excel表格里的文件突然格式全部乱了,怎么恢复?...
  11. android 电视安装apk文件损坏,安装电视软件时提示解析包出现问题怎么破?
  12. 「解析」netron 模型可视化
  13. 鱼塘钓鱼(fishing)
  14. android实现自动触摸,Android编程开发之多点触摸(Multitouch)实现方法
  15. vue中接口返回数据过大回显导致页面崩溃解决方法
  16. mpeg格式转换成mp4,mpeg转mp4
  17. 适合前端新手的十大网站
  18. 采集人物经历来佐证子平术
  19. 用python画小猪佩奇的编码有注释_啥是佩奇?使用Python自动绘画小猪佩奇的代码实例...
  20. MSDTC Service的访问权限

热门文章

  1. RunTime的使用-Category改变整个项目全部字体
  2. 翻译:微软style的并行计算
  3. Scala的基本语法总结
  4. Silverlight 3发布新版3.0.50106.0
  5. 三星android获取root权限,三星G9250(S6 Edge公开版全网通 Android 5.1)获取ROOT权限详解教程...
  6. 区块链技术开发三个优势
  7. valve 的设计_向Valve Portal开发人员学习游戏设计原则
  8. 数据通信技术(三:VLAN划分)
  9. Python多进程与进程锁的基本使用
  10. php字符串转换表达式,php处理字符串格式的计算表达式