sihyeonn commented on code in PR #12756:
URL: https://github.com/apache/apisix/pull/12756#discussion_r2601493623


##########
apisix/plugins/limit-count/limit-count-redis-cluster.lua:
##########
@@ -39,7 +40,56 @@ local script = core.string.compress_script([=[
 ]=])
 
 
-function _M.new(plugin_name, limit, window, conf)
+local script_sliding = core.string.compress_script([=[
+    assert(tonumber(ARGV[3]) >= 1, "cost must be at least 1")
+
+    local now = tonumber(ARGV[1])
+    local window = tonumber(ARGV[2])
+    local limit = tonumber(ARGV[3])
+    local cost = tonumber(ARGV[4])
+    local req_id = ARGV[5]
+
+    local window_start = now - window
+
+    redis.call('ZREMRANGEBYSCORE', KEYS[1], 0, window_start)
+
+    local current = redis.call('ZCARD', KEYS[1])
+
+    if current + cost > limit then
+        local earliest = redis.call('ZRANGE', KEYS[1], 0, 0, 'WITHSCORES')
+        local reset = 0
+        if #earliest == 2 then
+            reset = earliest[2] + window - now
+            if reset < 0 then
+                reset = 0
+            end
+        end
+        return {-1, reset}
+    end
+
+    for i = 1, cost do
+        local member = req_id .. ':' .. i
+        redis.call('ZADD', KEYS[1], now, member)
+    end

Review Comment:
   @nic-6443 
   
   Thanks for raising this concern!
   
   In this sliding-window implementation, we intentionally trade some Redis 
work per request for *exact* “N requests per rolling window” semantics. 
However, the memory and per-key load are bounded:
   
   - on every request we first call `ZREMRANGEBYSCORE` to drop all events 
outside of the current window and then enforce `current + cost <= limit` before 
inserting new members,
   - rejected requests do **not** insert new entries,
   - so for each key the ZSET cardinality is always `<= limit`, and Redis 
memory for this key is bounded by that limit.
   
   Because of this, even though we do one `ZADD` per allowed request, we don’t 
end up with unbounded growth like in some TTL-only designs – the sliding window 
state per key stays O(limit). Also, `window_type = "sliding"` is an opt-in mode 
and the docs explicitly call out that it is more expensive than the default 
fixed window, so it’s intended for use cases that really need accurate rolling 
windows and can accept the extra Redis cost.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to