Guava限流RateLimiter

2024-03-18 09:58
文章标签 限流 guava ratelimiter

本文主要是介绍Guava限流RateLimiter,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在互联网高并发场景下,限流是用来保证系统稳定性的一种手段,当系统遭遇瞬时流量激增时,可能会由于系统资源耗尽导致宕机。而限流可以把一小部分流量拒绝掉,保证大部分流量可以正常访问,从而保证系统只接收承受范围以内的请求,多余的请求给拒绝掉。

举个例子,节假日很多人都会出去玩,我们知道每个地铁站单位时间内可承受的运输能力是有限的,也就是每趟车承载的人数是有上限的,当达到这个上限以后,上不去的人就只能排队等待,当排队等待的人已经到地铁站口了,此时保安就会限制再进入地铁站了。此时的保安就是起到限流的作用

常用的限流算法有:漏桶算法、令牌桶算法

漏桶算法

漏桶算法很形象,我们可以想像有一个大桶,大桶底部有一个固定大小的洞,Web请求就像水一样,先进入大桶,然后以固定的速率从底部漏出来,无论进入桶中的水多么迅猛,漏桶算法始终以固定的速度来漏水
在这里插入图片描述

对应到Web请求就是

  • 当桶中无水时表示当前无请求等待,可以直接处理当前的请求
  • 当桶中有水时表示当前有请求正在等待处理,此时新来的请求也是需要进行等待处理
  • 当桶中水已经装满,并且进入的速率大于漏水的速率,水就会溢出来,此时系统就会拒绝新来的请求

令牌桶算法

令牌桶跟漏桶算法有点不一样,令牌桶算法也有一个大桶,桶中装的都是令牌,有一个固定的“人”在不停的往桶中放令牌,每个请求来的时候都要从桶中拿到令牌,要不然就无法进行请求操作

在这里插入图片描述

  • 当没有请求来时,桶中的令牌会越来越多,一直到桶被令牌装满为止,多余的令牌会被丢弃
  • 当请求的速率大于令牌放入桶的速率,桶中的令牌会越来越少,直止桶变空为止,此时的请求会等待新令牌的产生

漏桶算法 VS 令牌桶算法

  • 漏桶算法是桶中有水就需要等待,桶满就拒绝请求;而令牌桶是桶变空了需要等待令牌产生
  • 漏桶算法漏水的速率固定,令牌桶算法往桶中放令牌的速率固定
  • 令牌桶可以接收的瞬时流量比漏桶大,比如桶的容量为100,令牌桶会装满100个令牌,当有瞬时80个并发过来时可以从桶中迅速拿到令牌进行处理,而漏桶的消费速率固定,当瞬时80个并发过来时,可能需要进行排队等待

Guava中的限流实现RateLimiter

Guava中的限流使用的是令牌桶算法,RateLimiter提供了两种限流实现:

  • 平滑突发限流(SmoothBursty)
  • 平滑预热限流(SmoothWarmingUp)

什么是平滑突发限流?

每秒以固定的速率输出令牌,以达到平滑输出的效果

        //每秒5个令牌RateLimiter rateLimiter = RateLimiter.create(5);while(true){System.out.println("time:" + rateLimiter.acquire() + "s");}

输出结果:

time:0.0s
time:0.196802s
time:0.186141s
time:0.199164s
time:0.199221s
time:0.199338s
time:0.199493s

平均每个0.2秒左右,很均匀

当产生令牌的速率大于取令牌的速率时,是不需要等待令牌时间的

        //每秒5个令牌RateLimiter rateLimiter = RateLimiter.create(5);while(true){System.out.println("time:" + rateLimiter.acquire() + "s");//线程休眠,给足够的时间产生令牌Thread.sleep(1000);}

输出结果:

time:0.0s
time:0.0s
time:0.0s
time:0.0s
time:0.0s

由于令牌可以积累,所以我一次可以取多个令牌,只要令牌充足,可以快速响应

        //每秒5个令牌RateLimiter rateLimiter = RateLimiter.create(5);while(true){//一次取出5个令牌也可以快速响应System.out.println("______________________________________");System.out.println("time:" + rateLimiter.acquire(15) + "s");System.out.println("time:" + rateLimiter.acquire(1) + "s");System.out.println("time:" + rateLimiter.acquire(1) + "s");System.out.println("time:" + rateLimiter.acquire(1) + "s");}

输出结果:

______________________________________
time:0.0s
time:2.997305s
time:0.193227s
time:0.195574s
______________________________________
time:0.194769s
time:2.995363s
time:0.195592s
time:0.195186s
______________________________________
time:0.196013s
time:2.9972s
time:0.19612s
time:0.195975s
______________________________________
time:0.193164s

平滑预热限流?

平滑预热限流带有预热期的平滑限流,它启动后会有一段预热期,逐步将令牌产生的频率提升到配置的速率

这种方式适用于系统启动后需要一段时间来进行预热的场景

比如,我设置的是每秒5个令牌,预热期为5秒,那么它就不会是0.2左右产生一个令牌。在前5秒钟它不是一个均匀的速率,5秒后恢复均匀的速率

        //每秒5个令牌,预热期为5秒RateLimiter rateLimiter = RateLimiter.create(5,5, TimeUnit.SECONDS);while(true){//一次取出5个令牌也可以快速响应System.out.println("time:" + rateLimiter.acquire(1) + "s");System.out.println("time:" + rateLimiter.acquire(1) + "s");System.out.println("time:" + rateLimiter.acquire(1) + "s");System.out.println("time:" + rateLimiter.acquire(1) + "s");System.out.println("time:" + rateLimiter.acquire(1) + "s");System.out.println("-----------");}

输出结果:

time:0.0s
time:0.57874s
time:0.539854s
time:0.520102s
time:0.485491s
-----------
time:0.455969s
time:0.423133s
time:0.391189s
time:0.359336s
time:0.327898s
-----------
time:0.295409s
time:0.263682s
time:0.231618s
time:0.202781s
time:0.198914s
-----------
time:0.198955s
time:0.199052s
time:0.199183s
time:0.199296s
time:0.199468s
-----------
time:0.199493s
time:0.199687s
time:0.198785s
time:0.198893s
time:0.199373s
-----------

从输出结果可以看出来,前面的速率不均匀,到后面就逐渐稳定在0.2秒左右了

当然,Guava的RateLimiter只适用于单机的限流,在互联网分布式项目中可以借助其他中间件来实现限流的功能

 

设定业务场景:限制单个JVM进程10 qps的下单能力;RateLimiter原理

RateLimiter基于时间轴变化在每次请求时计算是否有可用Permit。总体思路:记录start、next两个时间点,每次申请Permit时,若current-next>stable interval可以申请Permit。

                                                                        注:图中一个刻度表示100ms

名字解释:

start:计时器启动时间

next:下次可生成Permit时间(current>next时,默认为上次申请Permit时间)

current:当前时间

stable interval:生成一个Permit时间间隔

步骤:

1、记录启动时间,记start=System.currentTimeMillis()

2、计算生成一个Permit的时间间隔,继上面例子1秒10qps,1000/10=100,即100ms生成一个Permit,记stable interval 为100ms

3、request1:申请一个Permit,next=0,current=start+1

a. current>next设置next=current

b. 计算request1等待时间,next<=current,request1不需要等待

c. 计算可用Permit,(current-next)/statble interval=0,没有可用Permit。怎么办?向未来借用Permit,next需要往后推迟一个stable interval。即:next=next+stable interval=start+2

request2:申请一个Permit,next=start+2,current=start+1.2

a. current<next,什么也不做

b. 计算request2等待时间,sleep time = next-current=0.8,request2需要等待sleep time(还request1借的时间)

c. 计算可用Permit,current<next,说明时间上次请求借用的额度还没有还完,所以本次请求只能再次向未来借用Permit,next需要往后推迟一个stable interval。即:next=next+stable interval=start+3

request3:申请一个Permit,next=start+3,current=start+8

a. current>next设置next=current

b. 计算request3等待时间,next<=current,request3不需要等待

c. 计算可用Permit,(current-next)/statble interval=5,所以本次请求不需要借用额度,注意额度最多只能存储用户设置的qps数量,这个例子是10

 

参考:
https://yq.aliyun.com/articles/696317

这篇关于Guava限流RateLimiter的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/821982

相关文章

基于Redis有序集合实现滑动窗口限流的步骤

《基于Redis有序集合实现滑动窗口限流的步骤》滑动窗口算法是一种基于时间窗口的限流算法,通过动态地滑动窗口,可以动态调整限流的速率,Redis有序集合可以用来实现滑动窗口限流,本文介绍基于Redis... 滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间

Java后端微服务架构下的API限流策略:Guava RateLimiter

Java后端微服务架构下的API限流策略:Guava RateLimiter 大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 在微服务架构中,API限流是保护服务不受过度使用和拒绝服务攻击的重要手段。Guava RateLimiter是Google开源的Java库中的一个组件,提供了简单易用的限流功能。 API限流概述 API限流通过控制请求的速率来防止

微服务之网关安全基于Zuul并实现网关限流

微服务网关安全 微服务架构下的问题 处理安全和业务逻辑耦合,增加了复杂性和变更成本 随着业务节点增加,认证服务器压力增大 多个微服务同时暴露,增加了外部访问的复杂性 通过网关处理流程 1、请求令牌。2、转发请求。3、返回令牌。4、转发令牌各客户端应用。5、携带令牌发送请求。6、校验令牌。7、返回校验结果信息。8、访问微服务。 实例 引入依赖 <dependencies><depe

谈谈经典限流方法—漏桶、令牌桶与Guava RateLimiter的实现

大数据技术与架构 点击右侧关注,大数据开发领域最强公众号! 暴走大数据 点击右侧关注,暴走大数据! 高并发的业务系统经常要接受大流量的考验,为了保证系统的响应度和稳定性,往往都需要对有风险的接口实施限流(rate limiting),更高大上的说法则是“流量整形”(traffic shaping)。限流的思想最初来源于计算机网络,有两种经典的方法:漏桶和令牌桶。本文先来稍微研究一下它们。

经典限流方法——漏桶、令牌桶与Guava RateLimiter的实现

点击上方蓝色字体,选择“设为星标” 回复”资源“获取更多资源 大数据技术与架构 点击右侧关注,大数据开发领域最强公众号! 暴走大数据 点击右侧关注,暴走大数据! 高并发的业务系统经常要接受大流量的考验,为了保证系统的响应度和稳定性,往往都需要对有风险的接口实施限流(rate limiting),更高大上的说法则是“流量整形”(traffic shaping)。限流的思想最初来源于计算机

使用信号量实现一个限流器:C++实战指南

使用信号量实现一个限流器:C++实战指南 在现代软件开发中,限流器(Rate Limiter)是一种常用的技术,用于控制系统的请求速率,防止系统过载。信号量(Semaphore)是一种强大的同步原语,可以用于实现限流器。本文将详细介绍如何在C++中使用信号量实现一个限流器,并提供完整的代码示例和详细的解释。 什么是限流器? 限流器是一种控制系统请求速率的机制,确保在单位时间内处理的请求数量不

Java 文件下载/上传限流算法

文章目录 一、算法思路二、限流的完整java代码实现三、注意点四、具体demo的github地址 在做文件下载功能时,为了避免下载功能将服务器的带宽打满,从而影响服务器的其他服务。我们可以设计一个限流器来限制下载的速率,从而限制下载服务所占用的带宽。 一、算法思路 定义一个数据块chunk(单位 bytes)以及允许的最大速率 maxRate(单位 KB/s)。通过maxR

常用的限流算法-令牌桶(Token Bucket)php版

令牌桶(Token Bucket)是一种常用的限流算法,用于控制流量的速率。其核心思想是以固定速率向桶中放入令牌,当请求到来时,从桶中取走一定数量的令牌,如果桶中没有足够的令牌,则拒绝请求或进行排队等待。 下面是如何在 PHP 中实现一个简单的令牌桶算法。 1. 令牌桶的基本概念 令牌的生成速度:令牌以固定速率生成并加入到桶中。桶的容量:桶中可以容纳的最大令牌数,防止令牌无限增长。请求的消耗

日志系统开发总结之Guava/EventBus

http://www.toutiao.com/a6351265293244301570/?tt_from=mobile_qq&utm_campaign=client_share&app=explore_article&utm_source=mobile_qq&iid=5840657922&utm_medium=toutiao_ios

利用Spring Boot实现微服务的API限流策略

利用Spring Boot实现微服务的API限流策略 大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! API限流是一种控制访问速率的机制,用于保护后端服务不被过载。Spring Boot提供了多种工具和方法来实现API限流策略。 API限流的概念 API限流通常通过限制在一定时间窗口内的请求数量来实现。常见的限流算法有令牌桶和漏桶算法。 使用Sprin