diff options
author | Lukas Fleischer <lfleischer@archlinux.org> | 2019-11-02 22:49:07 +0100 |
---|---|---|
committer | Lukas Fleischer <lfleischer@archlinux.org> | 2019-11-02 23:32:07 +0100 |
commit | 86e4cd0731b7164a8947fa3497483378aa1de209 (patch) | |
tree | fb81c6c2ab180e40cd9e5a4fe66f843689bc4edf /web | |
parent | a29155ac5bab3fcae46543ac97f64e3496e0194d (diff) | |
download | aur-86e4cd0731b7164a8947fa3497483378aa1de209.tar.gz aur-86e4cd0731b7164a8947fa3497483378aa1de209.tar.xz |
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 <lfleischer@archlinux.org>
Diffstat (limited to 'web')
-rw-r--r-- | web/lib/aurjson.class.php | 47 |
1 files changed, 32 insertions, 15 deletions
diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 1c31a65e..0ac586fe 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"); |