当前位置: 首页 >文章 > 我司用了 6 年的 Redis 分布式限流器,可以说是非常厉害了!
收藏
分享

我司用了 6 年的 Redis 分布式限流器,可以说是非常厉害了!

举报小虎转载君小虎转载君发布于 2020-04-26793阅读0点赞
旨在让大家认识下什么是限流?如何做一个简单的限流功能,面试要知道这是个什么东西。...

一、什么是限流?为什么要限流?
不知道大家有没有做过帝都的地铁,就是进地铁站都要排队的那种,为什么要这样摆长龙转圈圈?答案就是为了限流!因为一趟地铁的运力是有限的,一下挤进去太多人会造成站台的拥挤、列车的超载,存在一定的安全隐患。同理,我们的程序也是一样,它处理请求的能力也是有限的,一旦请求多到超出它的处理极限就会崩溃。为了不出现最坏的崩溃情况,只能耽误一下大家进站的时间。限流是保证系统高可用的重要手段!!!

由于互联网公司的流量巨大,系统上线会做一个流量峰值的评估,尤其是像各种秒杀促销活动,为了保证系统不被巨大的流量压垮,会在系统流量到达一定阈值时,拒绝掉一部分流量。

限流会导致用户在短时间内(这个时间段是毫秒级的)系统不可用,一般我们衡量系统处理能力的指标是每秒的QPS或者TPS,假设系统每秒的流量阈值是1000,理论上一秒内有第1001个请求进来时,那么这个请求就会被限流。

二、限流方案
1、计数器

Java内部也可以通过原子类计数器AtomicInteger、Semaphore信号量来做简单的限流。


2、漏桶算法

漏桶算法思路很简单,我们把水比作是请求,漏桶比作是系统处理能力极限,水先进入到漏桶里,漏桶里的水按一定速率流出,当流出的速率小于流入的速率时,由于漏桶容量有限,后续进入的水直接溢出(拒绝请求),以此实现限流。

3、令牌桶算法

令牌桶算法的原理也比较简单,我们可以理解成医院的挂号看病,只有拿到号以后才可以进行诊病。

系统会维护一个令牌(token)桶,以一个恒定的速度往桶里放入令牌(token),这时如果有请求进来想要被处理,则需要先从桶里获取一个令牌(token),当桶里没有令牌(token)可取时,则该请求将被拒绝服务。令牌桶算法通过控制桶的容量、发放令牌的速率,来达到对请求的限制。

4、Redis + Lua
很多同学不知道Lua是啥?个人理解,Lua脚本和 MySQL数据库的存储过程比较相似,他们执行一组命令,所有命令的执行要么全部成功或者失败,以此达到原子性。也可以把Lua脚本理解为,一段具有业务逻辑的代码块。

而Lua本身就是一种编程语言,虽然redis 官方没有直接提供限流相应的API,但却支持了 Lua 脚本的功能,可以使用它实现复杂的令牌桶或漏桶算法,也是分布式系统中实现限流的主要方式之一。

相比Redis事务,Lua脚本的优点:

减少网络开销:使用Lua脚本,无需向Redis 发送多次请求,执行一次即可,减少网络传输
原子操作:Redis 将整个Lua脚本作为一个命令执行,原子,无需担心并发
复用:Lua脚本一旦执行,会永久保存 Redis 中,,其他客户端可复用
Lua脚本大致逻辑如下:

通过KEYS[1] 获取传入的key参数
通过ARGV[1]获取传入的limit参数
redis.call方法,从缓存中get和key相关的值,如果为null那么就返回0
接着判断缓存中记录的数值是否会大于限制大小,如果超出表示该被限流,返回0
如果未超过,那么该key的缓存值+1,并设置过期时间为1秒钟以后,并返回缓存值+1
这种方式是本文推荐的方案,具体实现会在后边做细说。

5、网关层限流

限流常在网关这一层做,比如Nginx、Openresty、kong、zuul、Spring Cloud Gateway等,而像spring cloud - gateway网关限流底层实现原理,就是基于Redis + Lua,通过内置Lua限流脚本的方式。

三、Redis + Lua 限流实现
下面我们通过自定义注解、aop、Redis + Lua 实现限流,步骤会比较详细,为了小白能让快速上手这里啰嗦一点,有经验的老鸟们多担待一下。

1、环境准备
springboot 项目创建地址:https://start.spring.io,很方便实用的一个工具。

2、引入依赖包
pom文件中添加如下依赖包,比较关键的就是 spring-boot-starter-data-redis 和 spring-boot-starter-aop。


3、配置application.properties
在 application.properties 文件中配置提前搭建好的 redis 服务地址和端口。


4、配置RedisTemplate实例



限流类型枚举类

5、自定义注解
我们自定义个@Limit注解,注解类型为ElementType.METHOD即作用于方法上。

period表示请求限制时间段,count表示在period这个时间段内允许放行请求的次数。limitType代表限流的类型,可以根据请求的IP、自定义key,如果不传limitType属性则默认用方法名作为默认key。


6、切面代码实现


7、控制层实现

我们将@Limit注解作用在需要进行限流的接口方法上,下边我们给方法设置@Limit注解,在10秒内只允许放行3个请求,这里为直观一点用AtomicInteger计数。

8、测试
测试「预期」:连续请求3次均可以成功,第4次请求被拒绝。接下来看一下是不是我们预期的效果,请求地址:http://127.0.0.1:8080/limitTest1,用postman进行测试,有没有postman url直接贴浏览器也是一样。

可以看到第四次请求时,应用直接拒绝了请求,说明我们的 Springboot + aop + lua 限流方案搭建成功。

总结
以上 springboot + aop + Lua 限流实现是比较简单的,旨在让大家认识下什么是限流?如何做一个简单的限流功能,面试要知道这是个什么东西。上面虽然说了几种实现限流的方案,但选哪种还要结合具体的业务场景,不能为了用而用。

END

本文原创,未经作者允许不可转载!
更多内容,欢迎关注作者微信公众号:程序员内点事!


0条评论
别默默看啦~登录/注册一起参与讨论吧~

暂无评论

请选择举报理由

违反法律法规

侵犯个人权益

有害网站环境

更多训练营>>

为你推荐 · 训练营(全勤打卡报名费全额返累计全额返用户134,638人)

【10月】趣味MG动画制作训练营
距离开班仅剩8天20人已报名
文旅文创插画专项团练
距离开班仅剩11天23人已报名
【10月】零基础动态表情包创作训练营
距离开班仅剩20天21人已报名
猜你喜欢
你可能不知道的 ZooKeeper 知识点

2021-04-15

小虎转载君 发表

你可能不知道的 ZooKeeper 知识点
Jira入门教程 敏捷开发管理(二)

2018-04-12

产品研究笔记 发表

Jira入门教程 敏捷开发管理(二)
实现工具自由!开源的桌面工具箱

2021-08-04

小虎转载君 发表

实现工具自由!开源的桌面工具箱
字符串中的奇数

2021-07-18

小虎转载君 发表

字符串中的奇数
以1为边界的正方形

2021-07-25

小虎转载君 发表

以1为边界的正方形
特惠
充值
7折购
今日还在继续学习的你,太棒了!
7
折扣券可用于
年费无限VIP
立 即
使 用
此活动优惠不可与其他活动叠加使用
有效期:000000
消息
登录即可查看消息记录
建议
意见
官方
客服
在线咨询

您可以与在线客服进行沟通获得帮助

工作日:9:00~22:00节假日:9:00~18:00

联系在线客服
虎课
积分
免费学习91000+个教程!
配套素材、源文件一键下载!
昨日学员已学习了14,720
并提交了60份作业!
登录后立即学习!
loading
微信扫码关注即可登录
您需要同意协议才可以进行登录
登录虎课网,每天免费学课程全站 91000+ 视频会员教程 | 每日可免费学 1
为确保账户信息安全
请先进行真实姓名验证后进行充值付款
立即验证