membphis commented on code in PR #12605:
URL: https://github.com/apache/apisix/pull/12605#discussion_r2639094869
##########
apisix/plugins/limit-req/util.lua:
##########
@@ -14,60 +14,66 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-local math = require "math"
-local abs = math.abs
-local max = math.max
local ngx_now = ngx.now
-local ngx_null = ngx.null
local tonumber = tonumber
+local core = require("apisix.core")
local _M = {version = 0.1}
+local script = core.string.compress_script([=[
+ local state_key = KEYS[1] -- state_key (hash), fields:
"excess", "last"
+ local rate = tonumber(ARGV[1]) -- req/s
+ local now = tonumber(ARGV[2]) -- ms
+ local burst = tonumber(ARGV[3]) -- req/s
+ local commit = tonumber(ARGV[4]) -- 1/0
+
+ local vals = redis.call("HMGET", state_key, "excess", "last")
+ local prev_excess = tonumber(vals[1] or "0")
+ local prev_last = tonumber(vals[2] or "0")
+
+ local new_excess
+ if prev_last > 0 then
+ local elapsed = math.abs(now - prev_last)
+ new_excess = math.max(prev_excess - rate * (elapsed) / 1000 + 1000, 0)
+ else
+ new_excess = 0
+ end
+
+ if new_excess > burst then
+ return {0, new_excess}
+ end
+
+ if commit == 1 then
+ redis.call("HMSET", state_key, "excess", new_excess, "last", now)
+ redis.call("EXPIRE", state_key, 60)
+ end
+
+ return {1, new_excess}
+]=])
+
+
-- the "commit" argument controls whether should we record the event in shm.
function _M.incoming(self, red, key, commit)
local rate = self.rate
local now = ngx_now() * 1000
- key = "limit_req" .. ":" .. key
- local excess_key = key .. "excess"
- local last_key = key .. "last"
+ local state_key = "limit_req:{" .. key .. "}:state"
- local excess, err = red:get(excess_key)
- if err then
- return nil, err
- end
- local last, err = red:get(last_key)
- if err then
+ local commit_flag = commit and "1" or "0"
+
+ local res, err = red:eval(script, 1, state_key,
Review Comment:
we can use `evalsha`, avoid to repeat pass the `script` every time
official website: https://redis.io/docs/latest/commands/evalsha
here is a demo:
```lua
local redis = require "resty.redis"
-- Create redis instance
local red = redis:new()
-- Connect to Redis
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say("failed to connect: ", err)
return
end
-- Step 1: Load script and get SHA1
local script = "return redis.call('get', KEYS[1])"
local sha1, err = red:script("load", script)
if not sha1 then
ngx.say("failed to load script: ", err)
return
end
ngx.say("Script SHA1: ", sha1)
-- Step 2: Set a test key
red:set("mykey", "hello " .. ngx.time())
-- Step 3: Use evalsha to execute script
-- evalsha <sha1> <numkeys> <key1> [key2 ... ] [arg1 arg2 ...]
local res, err = red:evalsha(sha1, 1, "mykey")
if not res then
ngx.say("failed to evalsha: ", err)
return
end
ngx.say("Result: ", res) -- Output: hello
-- Put connection back to the pool
local ok, err = red:set_keepalive(10000, 100)
if not ok then
ngx.say("failed to set keepalive: ", err)
return
end
```
we can cache the `sha1` result
--
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]