redis令牌桶算法过期时间(redis实现令牌桶算法)

技术利用Redis如何实现令牌桶算法小编给大家分享一下利用Redis如何实现令牌桶算法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在限流算法

边肖将与您分享如何用Redis实现令牌桶算法。相信大部分人还不太了解,所以分享这篇文章给大家参考。希望你看完这篇文章会有很多收获。我们一起来看看吧!

在限流算法中,有一种令牌桶算法,可以处理短时突发流量,特别适用于真实环境中流量不均匀的情况。不会频繁触发限流,对来电者友好。

比如限流是10qps,大部分情况下不会超过,但偶尔会达到30qps,然后很快恢复正常。假设这种流量的爆发不会影响系统的稳定性,我们可以在一定程度上允许这种瞬间的流量爆发,从而给用户带来更好的可用性体验。这是使用令牌桶算法的地方。

令牌桶算法原理

如下图所示,这个算法的基本原理是有一个容量为x的令牌桶,每y个单位时间就有z个令牌放入这个桶中。如果桶中的令牌数超过x,将被丢弃。处理请求时,需要先从令牌桶中取出令牌,如果拿到令牌,继续处理;如果令牌不可用,请求将被拒绝。

利用Redis如何实现令牌桶算法

可见,在令牌桶算法中设置x、y、z的个数尤为重要。z应该略大于y单位时间的请求数,系统会长期处于这种状态;x是系统允许的瞬时最大请求数,系统不宜长时间处于这种状态,否则会频繁触发限流,说明流量超出预期,需要及时调查原因并采取相应措施。

00-1010之前,看到一些程序实现的令牌桶。将令牌放入桶中的方法是启动一个线程,每y个单位时间增加一次令牌的数量,或者在Timer中定期执行这个过程。我对这种方法不满意。原因有二。首先,它浪费线程资源。二是因为调度问题在执行时间上不准确。【相关推荐:Redis视频教程】

这里,计算确定令牌桶中令牌数量的方法。首先,从最后一个请求到这个请求过去了多长时间,是否达到了发放令牌的时间阈值,然后添加了多少令牌,可以将多少令牌放入桶中。

说话便宜!

让我们看看如何在Redis中实现它,因为它涉及到与Redis的许多交互。为了提高限流处理的吞吐量,减少程序与Redis的交互次数,采用了Redis支持的Lua脚本,Lua脚本的执行是原子性的,不需要担心脏数据。

代码节选自FireflySoft。RateLimit,不仅支持Redis的普通主从部署,还支持集群Redis,所以通过横向扩展可以提高吞吐量。为了阅读方便,这里加了一些注释,其实是没有的。

-定义返回值,为数组,包括:是否触发限流(1限流0遍)以及当前桶中的令牌数。

localret={}

ret[1]=0

- Redis集群分区Key,KEYS[1]为限流目标。

localcl_key='{ '.钥匙[1].'}'

-获取限流处罚的当前设置,当触发限流处罚时,会写入一个有到期时间的KV。

-如果有电流限制惩罚,则返回结果[1,-1]。

locallock_key=cl_key.-锁

locallock_val=redis.call('get ',lock_key)

如果iflock _ val==' 1 ’,则

ret[1]=1

ret[2]=-1

returnret

结束

-这里省略了部分代码。

-获取[上次将令牌放入桶中的时间]。如果未设置此时间,则令牌桶不存在。这时:

-一种情况是:第一次执行,此时定义的令牌桶已满。

-另一种情况是过流限制处理很长时间没有进行,导致这次KV携带的释放。

-此过期时间将超过令牌自然放入桶中的时间,直到桶满为止,因此令牌桶也应该满了。

locallast_time=redis.call('get ',st_key)

if(last_time==false)

然后

-此执行后剩余的令牌数:存储桶容量-此执行中消耗的令牌数。

bucket _ amount=产能-金额;

-更新令牌桶中的令牌数量,这里有一个到期时间。如果该程序长时间不执行,令牌桶KV将被回收。

ll('set',KEYS[1],bucket_amount,'PX',key_expire_time)
    -- 设置[上次向桶中放入令牌的时间],后边计算应放入桶中的令牌数量时会用到
    redis.call('set',st_key,start_time,'PX',key_expire_time)
    -- 返回值[当前桶中的令牌数]
    ret[2]=bucket_amount
    -- 无需其它处理
    return ret
end

-- 令牌桶存在,获取令牌桶中的当前令牌数
local current_value = redis.call('get',KEYS[1])
current_value = tonumber(current_value)

-- 判断是不是该放入新令牌到桶中了:当前时间-上次投放的时间 >= 投放的时间间隔
last_time=tonumber(last_time)
local last_time_changed=0
local past_time=current_time-last_time
if(past_time<inflow_unit)
then
 -- 不到投放的时候,直接从令牌桶中取走令牌
    bucket_amount=current_value-amount
else
 -- 需要放入一些令牌, 预计投放数量 = (距上次投放过去的时间/投放的时间间隔)*每单位时间投放的数量
    local past_inflow_unit_quantity = past_time/inflow_unit
    past_inflow_unit_quantity=math.floor(past_inflow_unit_quantity)
    last_time=last_time+past_inflow_unit_quantity*inflow_unit
    last_time_changed=1
    local past_inflow_quantity=past_inflow_unit_quantity*inflow_quantity_per_unit
    bucket_amount=current_value+past_inflow_quantity-amount
end

-- 这里省略部分代码

ret[2]=bucket_amount

-- 如果桶中剩余数量小于0,则看看是否需要限流惩罚,如果需要则写入一个惩罚KV,过期时间为惩罚的秒数
if(bucket_amount<0)
then
    if lock_seconds>0 then
        redis.call('set',lock_key,'1','EX',lock_seconds,'NX')
    end
    ret[1]=1
    return ret
end

-- 来到这里,代表可以成功扣减令牌,则需要更新令牌桶KV
if last_time_changed==1 then
    redis.call('set',KEYS[1],bucket_amount,'PX',key_expire_time)
 -- 有新投放,更新[上次投放时间]为本次投放时间
    redis.call('set',st_key,last_time,'PX',key_expire_time)
else
    redis.call('set',KEYS[1],bucket_amount,'PX',key_expire_time)
end
return ret

通过以上代码,可以看出,其主要处理过程是:

1、判断有没有被限流惩罚,有则直接返回,无则进入下一步。

2、判断令牌桶是否存在,不存在则先创建令牌桶,然后扣减令牌返回,存在则进入下一步。

3、判断是否需要投放令牌,不需要则直接扣减令牌,需要则先投放令牌再扣减令牌。

4、判断扣减后的令牌数,如果小于0则返回限流,同时设置限流惩罚,如果大于等于0则进入下一步。

5、更新桶中的令牌数到Redis。

你可以在任何一种开发语言的Redis库中提交并运行这段Lua script脚本,如果你使用的是.NET平台,可以参考这篇文章:ASP.NET Core中使用令牌桶限流(https://blog.bossma.cn/dotnet/asp-net-core-token-bucket-algorithm-of-rate-limit/) 。

关于FireflySoft.RateLimit

FireflySoft.RateLimit 是一个基于 .NET Standard 的限流类库,其内核简单轻巧,能够灵活应对各种需求的限流场景。

其主要特点包括:

  • 多种限流算法:内置固定窗口、滑动窗口、漏桶、令牌桶四种算法,还可自定义扩展。

  • 多种计数存储:目前支持内存、Redis两种存储方式。

  • 分布式友好:通过Redis存储支持分布式程序统一计数。

  • 限流目标灵活:可以从请求中提取各种数据用于设置限流目标。

  • 支持限流惩罚:可以在客户端触发限流后锁定一段时间不允许其访问。

  • 动态更改规则:支持程序运行时动态更改限流规则。

  • 自定义错误:可以自定义触发限流后的错误码和错误消息。

  • 普适性:原则上可以满足任何需要限流的场景。

以上是“利用Redis如何实现令牌桶算法”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/154052.html

(0)

相关推荐

  • dy刷粉网站推广马上刷,有没有抖音刷点赞双击的神器?

    技术dy刷粉网站推广马上刷,有没有抖音刷点赞双击的神器?我们刷抖音的时候都会发现我们经常看到的那些视频点赞量都是非常高的,而且被点击的概率也更高,可能你的朋友们也刷到了这个视频。所以抖音视频点赞量对于提高抖音视频热度是非

    测评 2021年11月11日
  • 如何理解MSSQL数据库后台进程

    技术如何理解MSSQL数据库后台进程本篇文章为大家展示了如何理解MSSQL数据库后台进程,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。与Oracle数据库类似,微软数据库产品MS

    攻略 2021年11月29日
  • php png失真的解决办法是什么

    技术php png失真的解决办法是什么这篇文章主要介绍“php png失真的解决办法是什么”,在日常操作中,相信很多人在php png失真的解决办法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望

    攻略 2021年10月23日
  • 产品销售明细表,如何用电子表格做销售记录单

    技术产品销售明细表,如何用电子表格做销售记录单1、首先产品销售明细表,新建并打开一个Excel表格,如图所示,输入销售清单的标题和正文。并把标题“商品销售明细清单”字体设为宋体,字号20,所在单元格合并居中。正文的文字居

    生活 2021年10月20日
  • 夜路,晚上走夜路150字作文

    技术夜路,晚上走夜路150字作文第一次走夜路_150字在记忆的大海中,一朵朵浪花拍打着海岸,又消失了夜路。可是,只有一朵浪花拍打着海岸,退去再打上海岸,再打上海岸,不断的从我的脑海重现那个第一次走夜路。记得在一个黑夜,我

    生活 2021年10月29日
  • 初识正则表达式

    技术初识正则表达式 初识正则表达式1 # 计算器 每天写一个小时2 # 选课系统 每天一个小时3 # re模块4 """正则表达式""" # *****非常重要5 """6 所有的模块要经历的两个步

    礼包 2021年11月15日