API调用次数限制实现
来源:互联网 发布:中国房地产数据报告 编辑:程序博客网 时间:2024/05/21 17:37
API调用次数限制实现
在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源, 通常来说我们会对于服务器上的各种接口进行调用次数的限制。比如对于某个 用户,他在一个时间段(interval)内,比如 1 分钟,调用服务器接口的次数不能够 大于一个上限(limit),比如说 100 次。如果用户调用接口的次数超过上限的话,就 直接拒绝用户的请求,返回错误信息。
这里采用Token Bucket(令牌桶)算法。
搜索资料的时候,发现 Guava 库当中也有一个 RateLimiter,其作用也是 用来进行限流,于是阅读了 RateLimiter 的源代码,查看一些 Google 的人是如何实现 Token Bucket 算法的。
参考: RateLimiter 和 SmoothRateLimiter
在 resync 方法中的这句代码 storedPermits = min(maxPermits, storedPermits+ (nowMicros - nextFreeTicketMicros)/stableIntervalMicros); 就是 RateLimiter 中计算 Token 数量的方法。没有使用计时器,而是使用时间戳的方式计算。这个做法给足了 信息。我们可以在 Bucket 中存放现在的 Token 数量,然后存储上一次补充 Token 的时间戳,当用户下一次请求获取一个 Token 的时候, 根据此时的时间戳,计算从上一个时间戳开始,到现在的这个时间点所补充的所有 Token 数量,加入到 Bucket 当中。
// com.google.common.util.concurrent.SmoothRateLimiter
private void resync(long nowMicros) { // if nextFreeTicket is in the past, resync to now if (nowMicros > nextFreeTicketMicros) { storedPermits = min(maxPermits, storedPermits + (nowMicros - nextFreeTicketMicros) / stableIntervalMicros); nextFreeTicketMicros = nowMicros; }}
实现代码如下:
public boolean access(String userId) { String key = genKey(userId); try (Jedis jedis = jedisPool.getResource()) { Map<String, String> counter = jedis.hgetAll(key); if (counter.size() == 0) { TokenBucket tokenBucket = new TokenBucket(System.currentTimeMillis(), limit - 1); jedis.hmset(key, tokenBucket.toHash()); return true; } else { TokenBucket tokenBucket = TokenBucket.fromHash(counter); long lastRefillTime = tokenBucket.getLastRefillTime(); long refillTime = System.currentTimeMillis(); long intervalSinceLast = refillTime - lastRefillTime; long currentTokensRemaining; if (intervalSinceLast > intervalInMills) { currentTokensRemaining = limit; } else { long grantedTokens = (long) (intervalSinceLast / intervalPerPermit); System.out.println(grantedTokens); currentTokensRemaining = Math.min(grantedTokens + tokenBucket.getTokensRemaining(), limit); } tokenBucket.setLastRefillTime(refillTime); assert currentTokensRemaining >= 0; if (currentTokensRemaining == 0) { tokenBucket.setTokensRemaining(currentTokensRemaining); jedis.hmset(key, tokenBucket.toHash()); return false; } else { tokenBucket.setTokensRemaining(currentTokensRemaining - 1); jedis.hmset(key, tokenBucket.toHash()); return true; } } }}
上面的方法是最初的实现方法,对于每一个 Token Bucket,在 Redis 上面,使用一个 Hash 进行表示,一个 Token Bucket 有 lastRefillTime 表示最后一次补充 Token 的时间,tokensRemaining 则表示 Bucket 中的剩余 Token 数量,access() 方法大致的步骤为:
- 当一个请求 Token进入 access() 方法后,先计算计算该请求的 Token Bucket 的 key;
- 如果这个 Token Bucket 在 Redis 中不存在,那么就新建一个 Token Bucket,然后设置该 Bucket 的 Token 数量为最大值减一(去掉了这次请求获取的 Token)。 在初始化 Token Bucket 的时候将 Token 数量设置为最大值这一点在后面还有讨论;
- 如果这个 Token Bucket 在 Redis 中存在,而且其上一次加入 Token 的时间到现在时间的时间间隔大于 Token Bucket 的 interval,那么也将 Bucket 的 Token 值重置为最大值减一;
- 如果 Token Bucket 上次加入 Token 的时间到现在时间的时间间隔没有大于 interval,那么就计算这次需要补充的 Token 数量,将补充过后的 Token 数量更新到 Token Bucket 中。
1. https://zhuanlan.zhihu.com/p/20872901?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
- Token Bucket
- Redis Incr
- Redis Eval
- Better Rate Limiting With Redis Sorted Sets
- Intro to rate limiting with Redis part1 andpart2
- Guava RateLimiter andGuava SmoothRateLimiter, 特别推荐 SmoothRateLimiter 中的文档部分
- Lua Reference,redis 中使用 lua 5.1
- Single Responsibility Principle
- High Cohesion, Loose Coupling
0 0
- API调用次数限制实现
- 递归调用的次数限制
- C#中实现软件使用次数限制
- C#实现限制软件的使用次数
- Java实现程序运行次数限制
- C#实现限制软件的使用次数
- 一小时内限制发送次数实现
- C#实现限制软件的使用次数
- PHP实现通过IP限制投票次数
- spring security实现限制登录次数功能
- 服务器访问次数限制实现的思路
- PHP实现登录失败次数限制
- 服务器访问次数限制实现的思路
- SpringBoot实现限制ip访问次数
- 【三】Springboot+Redis实现密码次数限制
- Node JS Express API token请求限制次数
- 调用API实现录音
- 限制输入次数的系统登陆的实现
- 关于正向代理和反向代理的精简描述
- AFN和ASI的区别
- Ubuntu更新16.04LTS后chrome字体发虚问题
- 面试题之求两个日期之间的天数差
- 直方图内最大矩形
- API调用次数限制实现
- 20160521模拟赛总结
- 【初中部 NOIP提高组 】模拟赛A
- ROLL A BALL (Unity 3D 入门) 游戏制作指导 - 滚珠游戏介绍
- Spring_Spring常见错误_error at ::0 can't find referenced pointcut解决办法
- <<c>>二叉查找树
- CSS的分类、选择器、文档结构
- TreeSet的排序两种实现方式Comparator和Comparable
- hdu_5690_All X(找循环节)