From c4386c6ab0d649d3b999f0cf98f6fccea9212ce5 Mon Sep 17 00:00:00 2001 From: LeftTry Date: Sun, 29 Sep 2024 12:23:46 +0600 Subject: [Feature] Add LRU cache for last filled ratelimit buckets --- lualib/redis_scripts/ratelimit_check.lua | 5 +++++ src/plugins/lua/ratelimit.lua | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lualib/redis_scripts/ratelimit_check.lua b/lualib/redis_scripts/ratelimit_check.lua index f24e0daf0..f066610a5 100644 --- a/lualib/redis_scripts/ratelimit_check.lua +++ b/lualib/redis_scripts/ratelimit_check.lua @@ -31,6 +31,8 @@ local leak_rate = tonumber(KEYS[3]) local max_burst = tonumber(KEYS[4]) local prefix = KEYS[1] local enable_dynamic = KEYS[7] == 'true' +local cache_prefix = KEYS[8] +local max_cache_size = KEYS[9] local dynr, dynb, leaked = 0, 0, 0 if not last then -- New bucket @@ -83,6 +85,9 @@ if burst + pending > 0 then burst = burst + pending if burst > 0 and burst > max_burst * dynb then + redis.call('ZREMRANGEBYRANK', cache_prefix, 0, -(max_cache_size + 1)) + redis.call('ZINCRBY', cache_prefix, 1, prefix) + return { 1, tostring(burst - pending), tostring(dynr), tostring(dynb), tostring(leaked) } end -- Increase pending if we allow ratelimit diff --git a/src/plugins/lua/ratelimit.lua b/src/plugins/lua/ratelimit.lua index 168d8d63a..c0783eac8 100644 --- a/src/plugins/lua/ratelimit.lua +++ b/src/plugins/lua/ratelimit.lua @@ -41,6 +41,8 @@ local settings = { -- Do not check ratelimits for these recipients whitelisted_rcpts = { 'postmaster', 'mailer-daemon' }, prefix = 'RL', + cache_prefix = 'RL_cache_prefix', + max_cache_size = 30, -- If enabled, we apply dynamic rate limiting based on the verdict dynamic_rate_limit = false, ham_factor_rate = 1.01, @@ -455,7 +457,8 @@ local function ratelimit_cb(task) { key = value.hash, task = task, is_write = true }, gen_check_cb(pr, bucket, value.name, value.hash), { value.hash, tostring(now), tostring(rate), tostring(bucket.burst), - tostring(settings.expire), tostring(bincr), tostring(dyn_rate_enabled) }) + tostring(settings.expire), tostring(bincr), tostring(dyn_rate_enabled), + settings.cache_prefix, settings.max_cache_size }) end end end -- cgit v1.2.3 From ee5d923a20ef1f2c09bfb0c71f416591adc2f481 Mon Sep 17 00:00:00 2001 From: LeftTry Date: Sun, 29 Sep 2024 12:46:30 +0600 Subject: [Minor] Change wrong logic of LRU cache to the right one --- lualib/redis_scripts/ratelimit_check.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lualib/redis_scripts/ratelimit_check.lua b/lualib/redis_scripts/ratelimit_check.lua index f066610a5..f8e34bbf7 100644 --- a/lualib/redis_scripts/ratelimit_check.lua +++ b/lualib/redis_scripts/ratelimit_check.lua @@ -86,7 +86,7 @@ if burst + pending > 0 then burst = burst + pending if burst > 0 and burst > max_burst * dynb then redis.call('ZREMRANGEBYRANK', cache_prefix, 0, -(max_cache_size + 1)) - redis.call('ZINCRBY', cache_prefix, 1, prefix) + redis.call('ZADD', cache_prefix, now, prefix) -- LRU cache is based on timestamps of buckets return { 1, tostring(burst - pending), tostring(dynr), tostring(dynb), tostring(leaked) } end -- cgit v1.2.3 From 94ff0ca172d108920119d42bac2060778d05e151 Mon Sep 17 00:00:00 2001 From: LeftTry Date: Sun, 29 Sep 2024 14:07:53 +0600 Subject: [Minor] Make names more informative --- lualib/redis_scripts/ratelimit_check.lua | 8 ++++---- src/plugins/lua/ratelimit.lua | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lualib/redis_scripts/ratelimit_check.lua b/lualib/redis_scripts/ratelimit_check.lua index f8e34bbf7..019996c11 100644 --- a/lualib/redis_scripts/ratelimit_check.lua +++ b/lualib/redis_scripts/ratelimit_check.lua @@ -31,8 +31,8 @@ local leak_rate = tonumber(KEYS[3]) local max_burst = tonumber(KEYS[4]) local prefix = KEYS[1] local enable_dynamic = KEYS[7] == 'true' -local cache_prefix = KEYS[8] -local max_cache_size = KEYS[9] +local lfb_cache_prefix = KEYS[8] +local lfb_max_cache_size = tonumber(KEYS[9]) local dynr, dynb, leaked = 0, 0, 0 if not last then -- New bucket @@ -85,8 +85,8 @@ if burst + pending > 0 then burst = burst + pending if burst > 0 and burst > max_burst * dynb then - redis.call('ZREMRANGEBYRANK', cache_prefix, 0, -(max_cache_size + 1)) - redis.call('ZADD', cache_prefix, now, prefix) -- LRU cache is based on timestamps of buckets + redis.call('ZREMRANGEBYRANK', lfb_cache_prefix, 0, -(lfb_max_cache_size + 1)) -- Keeping size of lfb cache + redis.call('ZADD', lfb_cache_prefix, now, prefix) -- LRU cache is based on timestamps of buckets return { 1, tostring(burst - pending), tostring(dynr), tostring(dynb), tostring(leaked) } end diff --git a/src/plugins/lua/ratelimit.lua b/src/plugins/lua/ratelimit.lua index c0783eac8..71ab52b4f 100644 --- a/src/plugins/lua/ratelimit.lua +++ b/src/plugins/lua/ratelimit.lua @@ -41,8 +41,8 @@ local settings = { -- Do not check ratelimits for these recipients whitelisted_rcpts = { 'postmaster', 'mailer-daemon' }, prefix = 'RL', - cache_prefix = 'RL_cache_prefix', - max_cache_size = 30, + lfb_cache_prefix = 'RL_cache_prefix', -- Last filled buckets cache prefix + lfb_max_cache_size = 30, -- If enabled, we apply dynamic rate limiting based on the verdict dynamic_rate_limit = false, ham_factor_rate = 1.01, @@ -443,7 +443,7 @@ local function ratelimit_cb(task) for pr, value in pairs(prefixes) do local bucket = value.bucket - local rate = (bucket.rate) / 1000.0 -- Leak rate in messages/ms + local rate = (bucket.rate) / 1000.0 -- Leak rate in messast filled bucketsages/ms local bincr = nrcpt if bucket.skip_recipients then bincr = 1 @@ -458,7 +458,7 @@ local function ratelimit_cb(task) gen_check_cb(pr, bucket, value.name, value.hash), { value.hash, tostring(now), tostring(rate), tostring(bucket.burst), tostring(settings.expire), tostring(bincr), tostring(dyn_rate_enabled), - settings.cache_prefix, settings.max_cache_size }) + tostring(settings.lfb_cache_prefix), tostring(settings.lfb_max_cache_size) }) end end end -- cgit v1.2.3 From fe428f6a8c6400a2e70c161afd41d55c97c7f027 Mon Sep 17 00:00:00 2001 From: LeftTry Date: Mon, 30 Sep 2024 00:53:21 +0600 Subject: [Minor] Small fix up --- src/plugins/lua/ratelimit.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/lua/ratelimit.lua b/src/plugins/lua/ratelimit.lua index 71ab52b4f..c20e61b17 100644 --- a/src/plugins/lua/ratelimit.lua +++ b/src/plugins/lua/ratelimit.lua @@ -443,7 +443,7 @@ local function ratelimit_cb(task) for pr, value in pairs(prefixes) do local bucket = value.bucket - local rate = (bucket.rate) / 1000.0 -- Leak rate in messast filled bucketsages/ms + local rate = (bucket.rate) / 1000.0 -- Leak rate in messages/ms local bincr = nrcpt if bucket.skip_recipients then bincr = 1 -- cgit v1.2.3