基于 Redis 实现限流功能
作者:@万明珠
喜欢这篇文章的话,就点个关注吧,会持续分享高质量Python文章,以及其它相关内容。
楔子
"限流"这种事情即使在生活中也很常见,比如我们银行办理业务,银行不可能给去的所有人同时服务,因为柜台就那么几个。所以可能一次只给 5 个人办理业务,其他的人只能在后面排队;再比如打饭等等,也是一样的道理。因为能提供服务的数量有限,所以必须要通过限流的方式。
在程序的层面上也是一样的,如果我们的系统只能支持 10 万人同时在线购物,但是某一天突然来了 100 万个用户,那么后果显然是服务器直接瘫痪。因此只能让"限流"的功能来维护,先让一部分用户进行购物,其它的人进行排队,这样就等保证整个系统进行运转了。
Redis 如何实现限流功能
关于限流所用的算法有两个:漏桶算法、令牌算法。
漏桶算法
漏桶算法的灵感源于漏斗,如下图所示:
首先,如果让你实现一个限流的算法你要怎么做呢?我们可以规定一个时间,比如 60s,在 60s 之内只能处理100个请求,如果超过了 100 个,那么就将多余的请求丢弃掉。但是这样存在一个问题:如果在 10s 内请求就已经 100 个,因此剩余的 50s 只能把再来的请求给丢弃掉。但是这 100 个请求又花了 10s 中就全部处理完了,那么剩余的 40s 做什么?显然这样做就存在这资源浪费的情况。于是可能有人想到使用队列的方式,设置队列的容量为100,任务处理完了就出队,然后等待处理的入队,这样就保证了资源的利用率,恭喜你,漏桶算法就是这么做的。
说实话从漏斗本身上想,也能猜出使用的是队列,一边进一边出。无论漏斗上面的水流有多少,漏斗下面的水都是均匀流出的。如果上面的水流量大于下面流出的水流量的话,那么漏斗会慢慢变满;反之,漏斗永远不会被装满,并一直流出。
漏桶算法的实现步骤是:先声明一个队列保存请求,这个队列相当于漏斗,当队列容量满了之后,就放弃新来的请求。然后执行的话则是通过声明另一个线程定期从队列中获取一个或多个任务执行,这样就实现了漏桶算法。
漏桶算法可以在编程语言这一层实现。
令牌算法
令牌算法指的是有一个程序以某种恒定的速度生成令牌,并存入令牌桶中,而每个请求需要先获取令牌才能执行,如果没有获取到令牌的话则放弃执行。如下图所示:
这种令牌算法,我们也可以使用 Python 的 threading 模块来实现。
更好的限流方案
在 Redis4.0,已经为我们实现了限流功能,并提供了原子的限流指令,再加上 Redis 这个天生的分布式程序就可以完美地实现限流了。
实现限流需要使用 Redis 提供的 Redis-Cell 模块,该模块使用的便是漏桶算法,使用起来也很简单,通过 cl.throttle 即可,但是我们需要提前安装。
前往:https://github.com/brandur/redis-cell/releases 下载对应系统的安装包,有源码编译和安装包安装两种方式,源码编译需要rust环境、比较复杂,所以推荐安装包安装。安装之后,直接解压即可,里面会有一个 libredis_cell.so 文件,执行 redis-cli 通过 module load 加载即可。
> cl.throttle mylimit 15 30 60
1)(integer)0 # 0 表示获取成功,1 表示拒绝
2)(integer)15 # 漏斗容量
3)(integer)14 # 漏斗剩余容量
4)(integer)-1 # 被拒绝之后,多长时间之后再试(单位:秒),-1 表示无需重试
5)(integer)2 # 多久之后漏斗完全空出来
其中 15 为漏斗的容量,30 / 60s 为漏斗的速率。
通过 Redis-Cell,我们则可以实现分布式原子级别的限流,更详细的使用可以查看官网。
如果觉得文章对您有所帮助,可以请囊中羞涩的作者喝杯柠檬水,万分感谢,愿每一个来到这里的人都生活愉快,幸福美满。
微信赞赏
支付宝赞赏
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器