This is an automated email from the ASF dual-hosted git repository.
nic-6443 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 06c15d327 perf(limit-count): use evalsha with NOSCRIPT fallback for
Redis script execution (#13363)
06c15d327 is described below
commit 06c15d3271a9d744332197d41e084519b7955429
Author: Nic <[email protected]>
AuthorDate: Thu May 14 16:09:01 2026 +0800
perf(limit-count): use evalsha with NOSCRIPT fallback for Redis script
execution (#13363)
---
.../limit-count/limit-count-redis-cluster.lua | 8 ++-
apisix/plugins/limit-count/limit-count-redis.lua | 8 ++-
t/plugin/limit-count-redis.t | 62 +++++++++++++++++-----
3 files changed, 62 insertions(+), 16 deletions(-)
diff --git a/apisix/plugins/limit-count/limit-count-redis-cluster.lua
b/apisix/plugins/limit-count/limit-count-redis-cluster.lua
index be7029b66..89a823e61 100644
--- a/apisix/plugins/limit-count/limit-count-redis-cluster.lua
+++ b/apisix/plugins/limit-count/limit-count-redis-cluster.lua
@@ -17,6 +17,7 @@
local redis_cluster = require("apisix.utils.rediscluster")
local core = require("apisix.core")
+local to_hex = require("resty.string").to_hex
local setmetatable = setmetatable
local tostring = tostring
@@ -37,6 +38,7 @@ local script = core.string.compress_script([=[
end
return {redis.call('incrby', KEYS[1], 0 - ARGV[3]), ttl}
]=])
+local script_sha = to_hex(ngx.sha1_bin(script))
function _M.new(plugin_name, limit, window, conf)
@@ -64,7 +66,11 @@ function _M.incoming(self, key, cost)
key = self.plugin_name .. tostring(key)
local ttl = 0
- local res, err = red:eval(script, 1, key, limit, window, cost or 1)
+ local res, err = red:evalsha(script_sha, 1, key, limit, window, cost or 1)
+ if err and core.string.has_prefix(err, "NOSCRIPT") then
+ core.log.warn("redis evalsha failed: ", err, ". Falling back to eval")
+ res, err = red:eval(script, 1, key, limit, window, cost or 1)
+ end
if err then
return nil, err, ttl
diff --git a/apisix/plugins/limit-count/limit-count-redis.lua
b/apisix/plugins/limit-count/limit-count-redis.lua
index ce78383fe..5580b22a0 100644
--- a/apisix/plugins/limit-count/limit-count-redis.lua
+++ b/apisix/plugins/limit-count/limit-count-redis.lua
@@ -16,6 +16,7 @@
--
local redis = require("apisix.utils.redis")
local core = require("apisix.core")
+local to_hex = require("resty.string").to_hex
local assert = assert
local setmetatable = setmetatable
local tostring = tostring
@@ -38,6 +39,7 @@ local script = core.string.compress_script([=[
end
return {redis.call('incrby', KEYS[1], 0 - ARGV[3]), ttl}
]=])
+local script_sha = to_hex(ngx.sha1_bin(script))
function _M.new(plugin_name, limit, window, conf)
@@ -65,7 +67,11 @@ function _M.incoming(self, key, cost)
key = self.plugin_name .. tostring(key)
local ttl = 0
- res, err = red:eval(script, 1, key, limit, window, cost or 1)
+ res, err = red:evalsha(script_sha, 1, key, limit, window, cost or 1)
+ if err and core.string.has_prefix(err, "NOSCRIPT") then
+ core.log.warn("redis evalsha failed: ", err, ". Falling back to eval")
+ res, err = red:eval(script, 1, key, limit, window, cost or 1)
+ end
if err then
return nil, err, ttl
diff --git a/t/plugin/limit-count-redis.t b/t/plugin/limit-count-redis.t
index 3adeb054a..47d529932 100644
--- a/t/plugin/limit-count-redis.t
+++ b/t/plugin/limit-count-redis.t
@@ -195,7 +195,41 @@ GET /hello
-=== TEST 7: set route, with redis host, port and right password
+=== TEST 7: flush redis script cache
+--- config
+ location /t {
+ content_by_lua_block {
+ local redis = require("resty.redis")
+ local red = redis:new()
+ red:set_timeout(1000)
+ local ok, err = red:connect("127.0.0.1", 6379)
+ if not ok then
+ ngx.say("failed to connect: ", err)
+ return
+ end
+ red:script("FLUSH")
+ red:flushall()
+ red:set_keepalive(10000, 100)
+ ngx.say("done")
+ }
+ }
+--- response_body
+done
+
+
+
+=== TEST 8: evalsha NOSCRIPT fallback after SCRIPT FLUSH
+--- request
+GET /hello
+--- error_code: 200
+--- grep_error_log eval
+qr/redis evalsha failed:.*Falling back to eval/
+--- grep_error_log_out
+redis evalsha failed: NOSCRIPT No matching script. Please use EVAL.. Falling
back to eval
+
+
+
+=== TEST 9: set route, with redis host, port and right password
--- config
location /t {
content_by_lua_block {
@@ -270,7 +304,7 @@ passed
-=== TEST 8: up the limit
+=== TEST 10: up the limit
--- pipelined_requests eval
["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
--- error_code eval
@@ -278,7 +312,7 @@ passed
-=== TEST 9: up the limit
+=== TEST 11: up the limit
--- pipelined_requests eval
["GET /hello1", "GET /hello", "GET /hello2", "GET /hello", "GET /hello"]
--- error_code eval
@@ -286,7 +320,7 @@ passed
-=== TEST 10: set route, with redis host, port and wrong password
+=== TEST 12: set route, with redis host, port and wrong password
--- config
location /t {
content_by_lua_block {
@@ -328,7 +362,7 @@ passed
-=== TEST 11: request for TEST 10
+=== TEST 13: request for TEST 10
--- request
GET /hello_new
--- error_code eval
@@ -338,7 +372,7 @@ failed to limit count: WRONGPASS invalid username-password
pair or user is disab
-=== TEST 12: multi request for TEST 10
+=== TEST 14: multi request for TEST 10
--- pipelined_requests eval
["GET /hello_new", "GET /hello1", "GET /hello1", "GET /hello_new"]
--- no_error_log
@@ -348,7 +382,7 @@ failed to limit count: WRONGPASS invalid username-password
pair or user is disab
-=== TEST 13: set route, with redis host, port and bad username and good
password
+=== TEST 15: set route, with redis host, port and bad username and good
password
--- config
location /t {
content_by_lua_block {
@@ -392,7 +426,7 @@ passed
-=== TEST 14: request for TEST 13
+=== TEST 16: request for TEST 13
--- request
GET /hello
--- error_code eval
@@ -402,7 +436,7 @@ failed to limit count: WRONGPASS invalid username-password
pair or user is disab
-=== TEST 15: set route, with redis host, port and good username and bad
password
+=== TEST 17: set route, with redis host, port and good username and bad
password
--- config
location /t {
content_by_lua_block {
@@ -446,7 +480,7 @@ passed
-=== TEST 16: request for TEST 15
+=== TEST 18: request for TEST 15
--- request
GET /hello
--- error_code eval
@@ -456,7 +490,7 @@ failed to limit count: WRONGPASS invalid username-password
pair or user is disab
-=== TEST 17: set route, with redis host, port and right username and password
+=== TEST 19: set route, with redis host, port and right username and password
--- config
location /t {
content_by_lua_block {
@@ -500,7 +534,7 @@ passed
-=== TEST 18: up the limit
+=== TEST 20: up the limit
--- pipelined_requests eval
["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
--- error_code eval
@@ -508,7 +542,7 @@ passed
-=== TEST 19: up the limit
+=== TEST 21: up the limit
--- pipelined_requests eval
["GET /hello1", "GET /hello", "GET /hello2", "GET /hello", "GET /hello"]
--- error_code eval
@@ -516,7 +550,7 @@ passed
-=== TEST 20: restore redis password to ''
+=== TEST 22: restore redis password to ''
--- config
location /t {
content_by_lua_block {