AlinsRan opened a new pull request, #14141:
URL: https://github.com/apache/apisix/pull/14141

   ### Description
   
   `limit-count` with templated keys or counts (for example `key: 
"${host}:${uri}"`, `count: "${http_count ?? 3}"`) did per-request work that 
only depends on the configuration.
   
   `core.utils.resolve_var` ran `ngx.re.gsub` with a function replacement on 
every call. With a function replacement, lua-resty-core allocates a fresh 4 KB 
output buffer per call and a captures table per match. The callback then split 
every variable on `??` with `ngx.re.split`, which had no `o` flag, so that 
regex was compiled again on every call.
   
   `limit-count` created a new limiter object for every request whenever 
`count` or `time_window` is a template or `rules` is used. It also rebuilt the 
rate-limit header names (three `gsub` calls for `header_prefix`) and the 
counter key prefix on every request.
   
   Changes:
   
   - `resolve_var` splits a template once into literal strings and variables 
(name, whether `??` is present, the default) and caches the result in an LRU of 
1024 templates. A call walks the segments into a buffer taken from `tablepool`. 
Return values, the resolved-variable count, the escaper and the `??` cases 
behave as before.
   - With the `local` policy, a limiter resolved per request is cached by 
plugin name, resolved count, time window and window type. A local limiter keeps 
its counters in the shared dict under the request key, so sharing one between 
requests and routes does not change any count. Redis policies are unchanged.
   - Rate-limit header names are cached in a bounded LRU keyed by the prefix 
and the base names, which come from the plugin configuration and plugin 
metadata.
   - The counter key prefix is cached per plugin conf table in a weak-keyed 
table. `conf_version` is memoized on the conf and `_meta.parent` is only set 
once, so the prefix of a conf never changes.
   
   One bug is fixed along the way: a variable getter that itself calls 
`resolve_var` used to cut the outer result short, because the old code kept the 
context and the resolved count in module-level upvalues (`t/core/utils.t` TEST 
17).
   
   Microbenchmark of `resolve_var` (LuaJIT, results kept alive, GC stopped 
while measuring allocation):
   
   | template | before | after |
   |---|---|---|
   | `${host}:${uri}` | 1.2–2.0 µs, 4432 B | 0.06 µs, 0 B |
   | `${dynamic_limit_value}` | 0.7–1.5 µs, 4288 B | 0.05 µs, 0 B |
   | `${http_x ?? 10}` | 0.8–1.5 µs, 4368 B | 0.05 µs, 0 B |
   
   Tests:
   
   - `t/core/utils.t` TEST 14–17: resolved-variable counts and `??` cases, the 
escaper, one template resolved with different values, and the re-entrant 
getter. TEST 14–16 also pass on master, TEST 17 fails there with `in-x`. TEST 
18: a getter that raises leaves no state behind.
   - `t/plugin/limit-count-rules.t` TEST 23–29: one key limited under counts 
that change per request, a count that fails to resolve rejecting only that 
request, two routes with the same rule keeping separate counters, a 
configuration change starting a new counter, header names following a plugin 
metadata change, and a templated count without `rules`.
   
   #### Which issue(s) this PR fixes:
   
   None.
   
   ### Checklist
   
   - [x] I have explained the need for this PR and the problem it solves
   - [x] I have explained the changes or the new features added to this PR
   - [x] I have added tests corresponding to this change
   - [ ] I have updated the documentation to reflect this change
   - [x] I have verified that this change is backward compatible (If not, 
please discuss on the [APISIX mailing 
list](https://github.com/apache/apisix/tree/master#community) first)
   


-- 
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