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

   ### Description
   
   `run_global_rules()` rebuilds the same plugin set on every phase, and 
`_M.filter()` scans every loaded plugin to do it. With a `global_rule` enabling 
a single plugin and ~108 plugins loaded, one plain request walks the full 
plugin list 9 times.
   
   Two independent changes, one commit each so their contributions can be 
judged separately.
   
   **1. Iterate the configured plugins instead of every loaded plugin**
   
   `_M.filter()` loops `local_plugins` and asks whether the resource configured 
each one, discarding 107 of 108 lookups. The fast path loops `user_plugin_conf` 
instead and resolves names through `local_plugins_hash`. The slow path is kept 
for resources configuring a large fraction of the loaded set, where the added 
sort would outweigh the saved scan.
   
   Ordering is load-bearing and the two paths derive it differently: the slow 
path inherits it from the already-sorted `local_plugins`, while the fast path 
sees `pairs()` order and must sort it back. `sort_plugin` compares priority 
alone and `sort_tab` is not stable, so plugins sharing a priority could come 
out differently. `local_plugins_order` records each plugin's position and 
`sort_matched_plugin` falls back to it, so both paths agree.
   
   **2. Reuse the filtered global-rule set across phases**
   
   Route plugins are computed once and reused through `api_ctx.plugins`; global 
rules were not. The result is now cached on `api_ctx`, keyed by the merged 
rule's `modifiedIndex` and by the matched route.
   
   The route belongs in the key: plugins declaring `run_policy = 
"prefer_route"` are skipped when the route configures the same plugin, and 
`api_ctx.matched_route` is replaced when a consumer's configuration is merged 
in — after `rewrite` has run but before `access`.
   
   Since the table now outlives a phase, it moves to the `global_plugins` pool 
and is released in `http_log_phase` instead of at the end of every phase.
   
   ### Measurements
   
   Measured on an APISIX 3.2-based fork carrying the same two changes, single 
worker, CPU-pinned (worker and load generator on separate cores), wrk2, 5 runs 
each, median. `global_rule` enabling prometheus:
   
   | build | rps |
   |---|---|
   | baseline | 27,754 |
   | iterate configured plugins | 32,723 (+17.9%) |
   | + cross-phase reuse | measured separately at +12.2% on its own baseline |
   
   The two numbers come from different runs with different baselines and are 
**not** additive — the second change cuts the number of `filter()` calls per 
request from 9 to 1, which necessarily shrinks what the first one saves. I have 
not measured the 2x2 matrix that would separate them properly. Both are also 
unmeasured on master itself.
   
   ### Tests
   
   - `t/plugin/filter-fast-path.t` — the fast path yields the same order as 
`local_plugins`
   - `t/plugin/global-rule-phase-cache.t` — every phase still runs off the 
cached set; `body_filter` still runs per response buffer on a chunked response; 
the set is rebuilt when the global rule changes
   
   **Known gap:** the fork also carries a case proving the cached set is 
rebuilt when a consumer merge replaces `matched_route` (verified there by 
deleting the route key and watching it fail). It observes `prefer_route` 
through prometheus metrics, and I could not port it: `Test::Nginx` restarts 
nginx between blocks with differing `--- config`, and the metrics live in a 
per-process shared dict, so cross-block observation resets. Since `prometheus` 
and `skywalking` are the only `prefer_route` plugins, I did not find another 
observation point. The route cache key is therefore untested here — pointers 
welcome.
   
   Equal-priority ordering is likewise uncovered: all 108 built-in plugins have 
unique priorities, and constructing a collision needs a custom plugin. The 
tie-breaker guards custom plugins.
   
   ### Checklist
   
   - [x] I have explained why we need this PR and what problem it solves
   - [x] I have explained the changes in this PR
   - [x] I have added tests
   - [ ] I have updated the documentation — no user-facing behaviour change
   


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