Reading Building a sliding window rate limiter with Redis, and w/o addressing the actual logic (which may or may not work).
Optimize by:
- Lua seems a much better choice: idiompotent, portable, server-side, less bandwidth, atomic...
- The call to
ZRANGEBYSCORE
seems to be unused, should be commented out if so - Looking at the use of
ZRANGE
, it appears thatZCARD
it what's actually needed
The (untested) Lua snippet:
local tok = KEYS[1]
local now, win = tonumber(ARGV[1]), tonumber(ARGV[2])
-- redis.call('ZRANGEBYSCORE', tok, 0, now - win)
local ret = redis.call('ZCARD', tok)
redis.call('ZADD', tok, now, now)
redis.call('EXPIRE', tok, win)
return ret
The (untested) PHP:
// composer require predis/predis
require_once __DIR__ . '/vendor/autoload.php';
$maxCallsPerHour = 5000;
$slidingWindow = 3600;
$now = microtime(true);
$accessToken = md5('access-token');
$client = new Predis\Client();
$result = $client->evalsha('the-sha1-of-the-snippet');
$remaining = max(0, $maxCallsPerHour - count($result));
if ($remaining > 0) {
echo sprintf('%s: Allowed and %d remaining', $now, $remaining) . PHP_EOL;
} else {
echo sprintf('%s: Not allowed', $now) . PHP_EOL;
}
This is the lua script we're using atm: