使用redis来实现rate limiter
实现rate limiter 的想法:
1 Make sure: the gap between two requests >= 1/5
Acquire()
If (now - mLastTime >= 0.2)
mLastTime = Now;
Return True;
Else
Return False;
这种方法会导致0.3s 后 0.4s 的请求失败
2 Algorithm of time-‐bucket
Acquire()
s = GetCurrentSecond();
If ( mCounter[s] >= 5 )
Return False;
Else
mCounter[s]++;
Return True;
3 time-bucket with database
Expire: Set a timeout on key. After the timeout has expired, the key will automatically be deleted.
Database.Expire(s, 1); 帮助我们自动删除一个key在1s后。
Acquire()
s = GetCurrentSecond();
counter = Database.Get(s);
If counter != NULL AND counter >= 5
Return False;
Else
Database.Increase(s, 1);
Database.Expire(s, 1);
Return True;
我们使用 Redis 来做:
我们绑定ip和时间, 这样限制api的访问量。
FUNCTION LIMIT_API_CALL(ip)
ts = CURRENT_UNIX_TIME()
keyname = ip+":"+ts
current = GET(keyname)
IF current != NULL AND current > 10 THEN
ERROR "too many requests per second"
ELSE
MULTI // Marks the start of a transaction block.
INCR(keyname,1)
EXPIRE(keyname,10)
EXEC
PERFORM_API_CALL()
END
Redis如何expire一个key
Redis通过passive 和 active 两种方式来进行的:
消极 就是当我们访问一个key时,发现它time out了,就删除它。
积极 就是我们主动随机的选出20个key在每10秒钟的间隔,然后删除过期的key。如果这个过期的比例高于25%,我们就在执行一遍积极删除。
Reference:
https://redis.io/commands/INCR
https://redis.io/commands/expire