Commit 86e4cd07 authored by Lukas Fleischer's avatar Lukas Fleischer
Browse files

aurjson: use APCu/memcached for rate limiting



There's no need to use permanent storage for rate limiting information;
try to keep it in memory if caching is enabled.

From experiments with our live setup, this reduces the number of
INSERT/DELETE operations per second from 15 to almost 0. Disk writes on
the server hosting the AUR are reduced by 90% (from ~3MB/s to ~300kB/s).
Signed-off-by: Lukas Fleischer's avatarLukas Fleischer <lfleischer@archlinux.org>
parent a29155ac
...@@ -152,23 +152,26 @@ class AurJSON { ...@@ -152,23 +152,26 @@ class AurJSON {
return false; return false;
} }
$window_length = config_get("ratelimit", "window_length");
$this->update_ratelimit($ip); $this->update_ratelimit($ip);
$stmt = $this->dbh->prepare("
SELECT Requests FROM ApiRateLimit
WHERE IP = :ip");
$stmt->bindParam(":ip", $ip);
$result = $stmt->execute();
if (!$result) { $status = false;
return false; $value = get_cache_value('ratelimit:' . $ip, $status);
} if (!$status) {
$stmt = $this->dbh->prepare("
SELECT Requests FROM ApiRateLimit
WHERE IP = :ip");
$stmt->bindParam(":ip", $ip);
$result = $stmt->execute();
if (!$result) {
return false;
}
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row['Requests'] > $limit) { $value = $row['Requests'];
return true;
} }
return false;
return $value > $limit;
} }
/* /*
...@@ -182,9 +185,23 @@ class AurJSON { ...@@ -182,9 +185,23 @@ class AurJSON {
$window_length = config_get("ratelimit", "window_length"); $window_length = config_get("ratelimit", "window_length");
$db_backend = config_get("database", "backend"); $db_backend = config_get("database", "backend");
$time = time(); $time = time();
// Clean up old windows
$deletion_time = $time - $window_length; $deletion_time = $time - $window_length;
/* Try to use the cache. */
$status = false;
$value = get_cache_value('ratelimit-ws:' . $ip, $status);
if (!$status || ($status && $value < $deletion_time)) {
if (set_cache_value('ratelimit-ws:' . $ip, $time, $window_length) &&
set_cache_value('ratelimit:' . $ip, 1, $window_length)) {
return;
}
} else {
$value = get_cache_value('ratelimit:' . $ip, $status);
if ($status && set_cache_value('ratelimit:' . $ip, $value + 1, $window_length))
return;
}
/* Clean up old windows. */
$stmt = $this->dbh->prepare(" $stmt = $this->dbh->prepare("
DELETE FROM ApiRateLimit DELETE FROM ApiRateLimit
WHERE WindowStart < :time"); WHERE WindowStart < :time");
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment