[PATCH] aurjson: use APCu/memcached for rate limiting
From experiments with our live setup, this reduces the number of INSERT/DELETE operations per second from 15 to almost 0. Disk writes on
There's no need to use permanent storage for rate limiting information; try to keep it in memory if caching is enabled. the server hosting the AUR are reduced by 90% (from ~3MB/s to ~300kB/s). Signed-off-by: Lukas Fleischer <lfleischer@archlinux.org> --- web/lib/aurjson.class.php | 47 ++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 1c31a65..0ac586f 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -152,23 +152,26 @@ class AurJSON { return false; } - $window_length = config_get("ratelimit", "window_length"); $this->update_ratelimit($ip); - $stmt = $this->dbh->prepare(" - SELECT Requests FROM ApiRateLimit - WHERE IP = :ip"); - $stmt->bindParam(":ip", $ip); - $result = $stmt->execute(); - if (!$result) { - return false; - } + $status = 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); - if ($row['Requests'] > $limit) { - return true; + $row = $stmt->fetch(PDO::FETCH_ASSOC); + $value = $row['Requests']; } - return false; + + return $value > $limit; } /* @@ -182,9 +185,23 @@ class AurJSON { $window_length = config_get("ratelimit", "window_length"); $db_backend = config_get("database", "backend"); $time = time(); - - // Clean up old windows $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(" DELETE FROM ApiRateLimit WHERE WindowStart < :time"); -- 2.23.0
participants (1)
-
Lukas Fleischer