这篇文章主要介绍如何实现API接口限流,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
同样,在互联网行业中,也存在这样得场景,我们把它称为——限流,为什么要限流呢,原因如下:
在系统上线初期,用户量和访问量不大得时候,一般部署几台应用服务器,数据库做一个读写分离就基本上抗得住,但随着时间的推移,业务的发展,用户量和日活得增加,系统所承受的压力越来越大,我么都知道,应用服务器扩容很方便,但数据库扩容就有些麻烦,如果请求数据库的量太大的话,或者遇到恶意攻击,数据库极有可能宕机,最后导致整个网站不可用。
为了避免这样的事情发生,我们通常要限制住用户的请求次数。对于合法的用户,我们要限制单位时间内用户调用接口的次数,对于恶意攻击者,直接将他放入黑名单中。
我们通常用Redis中的zset数据结构来做限流。由于zset底层是用跳跃表存储数据的,按score字段从小到大排序,我们可以把时间戳存入score字段。随着时间的流逝,把每一次请求的时间戳存入score中,而member呢?随便存储什么无所谓啦,但不要存储太大的数据。如下图:
假如我们要求接口的调用一分钟不能超过100次,那么图中橙色矩形区域是一个时间段范围内的时间窗口,矩形的有边框是当前时间,它随着时间的流逝一点一点向右移动,矩形左边框是1min前,矩形的宽度就是1min。我们通过Redis的zcount命令很容易计算出这个时间范围内的数据量,如果数据量超出100,说明用户请求的太快了,应该进行限流的操作。下面来看一段简单的代码:
/**
* 基于zset限流
* @param key redis key
* @param maxCount 指定时间内最大通过个数
* @param timeRange 时间窗范围,单位:秒
* @return 是否可以继续请求
*/
public static boolean rateLimiterByZset(String key,int maxCount,int timeRange){
try (Jedis jedis = jedisPool.getResource()) {
long currentTime = new Date().getTime(); //当前时间戳
long secondTime = currentTime-timeRange*1000; //second秒前的时间戳
long memberCount = jedis.zcount(key,secondTime,currentTime);
if(memberCount >= maxCount){
return false;
}
jedis.zadd(key,currentTime,currentTime+"");
//删除时间框外的数据,因为它们已经没有用了
jedis.zremrangeByScore(key,0,secondTime);
}
return true;
}
哈哈,就这么简单。有一点要注意的是,请大家及时删除时间框(也就是上图中左边框外)范围外的数据,因为它们已经没有用了,留着非常消耗内存资源。
大家会不会有这样的疑问:对zset操作这么频繁,会不会有性能上的问题呀?其实大家不必太担心,毕竟Redis的数据结构都是经过精心设计的,性性能很高,大家可以参考小编的这篇文章,来学习Redis的数据结构。
从数据存储角度分析Redis性能为何如此高
刘莅,公众号:向代码致敬从数据存储角度分析Redis性能为何如此高
测试程序和输出效果如下:
@Test public void test1() throws Exception{ int i = 1; while(true){ Thread.sleep(5); boolean flag = RedisRateLimiter.rateLimiterByZset("keysss",10,1); if(flag){ System.out.println("第"+i+"个请求成功"); }else{ System.out.println("第"+i+"个被限流"); } i++; } }
第1个请求成功第2个请求成功第3个请求成功第4个请求成功第5个请求成功第6个请求成功第7个请求成功第8个请求成功第9个请求成功第10个请求成功第11个被限流第12个被限流...第42个被限流第43个被限流第44个请求成功第45个请求成功第46个请求成功第47个请求成功第48个请求成功第49个请求成功第50个请求成功第51个请求成功第52个请求成功第53个请求成功第54个被限流第55个被限流...
以上是“如何实现API接口限流”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。