-
Notifications
You must be signed in to change notification settings - Fork 2.7k
feat: ai rate limiting redis support #12751
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 18 commits
2194930
680af73
75b0aa7
14e6fce
d5552d8
82323ae
3b8e2ad
5204105
c857713
73737c1
b303401
0b76863
f86b98f
706bcb7
a10b0e7
ac70f00
f9ceaeb
5276e0c
7f02e0e
a6b71af
a716a34
5c409c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,11 +14,12 @@ | |||||||||||||||||||||||||||||||||||||||||||||
| -- See the License for the specific language governing permissions and | ||||||||||||||||||||||||||||||||||||||||||||||
| -- limitations under the License. | ||||||||||||||||||||||||||||||||||||||||||||||
| -- | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| local redis_cluster = require("apisix.utils.rediscluster") | ||||||||||||||||||||||||||||||||||||||||||||||
| local core = require("apisix.core") | ||||||||||||||||||||||||||||||||||||||||||||||
| local ngx = ngx | ||||||||||||||||||||||||||||||||||||||||||||||
| local setmetatable = setmetatable | ||||||||||||||||||||||||||||||||||||||||||||||
| local tostring = tostring | ||||||||||||||||||||||||||||||||||||||||||||||
| local util = require("apisix.plugins.limit-count.util") | ||||||||||||||||||||||||||||||||||||||||||||||
| local ngx_timer_at = ngx.timer.at | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| local _M = {} | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -28,17 +29,6 @@ local mt = { | |||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| local script = core.string.compress_script([=[ | ||||||||||||||||||||||||||||||||||||||||||||||
| assert(tonumber(ARGV[3]) >= 1, "cost must be at least 1") | ||||||||||||||||||||||||||||||||||||||||||||||
| local ttl = redis.call('ttl', KEYS[1]) | ||||||||||||||||||||||||||||||||||||||||||||||
| if ttl < 0 then | ||||||||||||||||||||||||||||||||||||||||||||||
| redis.call('set', KEYS[1], ARGV[1] - ARGV[3], 'EX', ARGV[2]) | ||||||||||||||||||||||||||||||||||||||||||||||
| return {ARGV[1] - ARGV[3], ARGV[2]} | ||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||
| return {redis.call('incrby', KEYS[1], 0 - ARGV[3]), ttl} | ||||||||||||||||||||||||||||||||||||||||||||||
| ]=]) | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| function _M.new(plugin_name, limit, window, conf) | ||||||||||||||||||||||||||||||||||||||||||||||
| local red_cli, err = redis_cluster.new(conf, "plugin-limit-count-redis-cluster-slot-lock") | ||||||||||||||||||||||||||||||||||||||||||||||
| if not red_cli then | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -57,26 +47,33 @@ function _M.new(plugin_name, limit, window, conf) | |||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| function _M.incoming(self, key, cost) | ||||||||||||||||||||||||||||||||||||||||||||||
| local red = self.red_cli | ||||||||||||||||||||||||||||||||||||||||||||||
| local limit = self.limit | ||||||||||||||||||||||||||||||||||||||||||||||
| local window = self.window | ||||||||||||||||||||||||||||||||||||||||||||||
| key = self.plugin_name .. tostring(key) | ||||||||||||||||||||||||||||||||||||||||||||||
| function _M.incoming(self, key, cost, dry_run) | ||||||||||||||||||||||||||||||||||||||||||||||
| local commit = true | ||||||||||||||||||||||||||||||||||||||||||||||
| if dry_run ~= nil then | ||||||||||||||||||||||||||||||||||||||||||||||
| commit = not dry_run | ||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| local ttl = 0 | ||||||||||||||||||||||||||||||||||||||||||||||
| local res, err = red:eval(script, 1, key, limit, window, cost or 1) | ||||||||||||||||||||||||||||||||||||||||||||||
| return util.redis_incoming(self, self.red_cli, key, commit, cost) | ||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| if err then | ||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err, ttl | ||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| local remaining = res[1] | ||||||||||||||||||||||||||||||||||||||||||||||
| ttl = res[2] | ||||||||||||||||||||||||||||||||||||||||||||||
| local function log_phase_incoming_thread(premature, self, key, cost) | ||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code should be placed in the ai-rate-limiting plugin, not in the limit-count plugin itself, because this code is only useful for ai-rate-limiting.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree. Similar logic also appears in the limit-conn. apisix/apisix/plugins/limit-conn/limit-conn-redis.lua Lines 60 to 81 in 7e907a5
If I put this logic into ai-rate-limiting plugin, it will make the plugin too complicated. I have to copy a lot of logic from limit-count. Currently, the ai-rate-limiting is just a simple wrapper of limit-count. Or, do you think I need to rewrite the ai-rate-limiting to something like limit-ai-redis.lua and limit-ai-redis-cluster.lua?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR is quite large and hard to review. If you agree, I can split it into 3 separate PRs:
|
||||||||||||||||||||||||||||||||||||||||||||||
| return util.redis_log_phase_incoming(self, self.red_cli, key, cost) | ||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| function _M.log_phase_incoming(self, key, cost, dry_run) | ||||||||||||||||||||||||||||||||||||||||||||||
| if dry_run then | ||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| if remaining < 0 then | ||||||||||||||||||||||||||||||||||||||||||||||
| return nil, "rejected", ttl | ||||||||||||||||||||||||||||||||||||||||||||||
| local ok, err = ngx_timer_at(0, log_phase_incoming_thread, self, key, cost) | ||||||||||||||||||||||||||||||||||||||||||||||
| if not ok then | ||||||||||||||||||||||||||||||||||||||||||||||
| core.log.error("failed to create timer: ", err) | ||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||
| return 0, remaining, ttl | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| return ok | ||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.