Files
RustProxy/docs/PROXY_HOTPATH_0.34.0.md
T
2026-10-17 20:34:13 +02:00

85 lines
4.6 KiB
Markdown

# RustProxy 0.34.0 — reverse-proxy hot-path candidate
## What was changed
1. **Routes:** `Snapshot.routes` and `fallbacks` now hold
`Arc<CompiledRoute>` handles. The same compiled location is shared across
hostname aliases. `observe` resolves vhost/location once from the accepted
listener/TLS-state and stores a request-local handle. `forward_request`
consumes the same immutable snapshot/route; internal error fallbacks still
resolve the explicitly configured named location independently.
2. **Host matching:** wildcard candidate strings are generated lazily only
after an exact host failed, without changing longest-specific-suffix order.
3. **LB:** single-backend non-cookie pools use a direct admitted lease without
temporary candidate vectors or scheduler mutex. Multi-backend weighted
round-robin retains its ordering and mutex; least-connection/traffic,
adaptive, IP hash and cookie-affinity retain their behavior. IP hash avoids
repeated canonicalization/temporary `format!` strings for each candidate.
4. **Health:** a `healthy_cached` atomic allows checking healthy backends
without the health mutex; all state transitions remain inside the existing
state machine, including passive quarantine and half-open recovery.
Resolved active/passive per-member policies are held in shared immutable
`Arc` handles so a new request lease does not deep-clone health paths,
headers or optional host strings.
5. **Fallback/retry:** request body+HeaderMap replay templates are made only
for configured error fallbacks. Retry headers are cloned only for eligible
safe replay requests where another member or H2 graceful close makes retry
possible; writes, streaming bodies and WebSockets are not replayed.
6. **Telemetry:** three per-request mutex-backed scalar tags are now atomic;
their original event strings and `Option<bool>` log fields are decoded at
exchange completion. Request ID, method, host and path are moved into the
terminal log record instead of deep-cloned in Drop; the traffic sample
still receives its own required copies. Logs avoid a broadcast clone if
there are no subscribers, preserving history, sink and counters.
## Preserved boundaries
All vhost, ACL, GeoIP, Basic Auth, Tinyauth, WebSocket, retry, cache,
transform, compression, log, metrics, `sendfile`, PHP-FPM, HTTPS/H2/H3 and
admin panel configuration paths are intended to remain compatible. Defaults
and SQLite schema are unchanged; no new performance toggle was added. The
optimization reuses route objects within one immutable snapshot but does not
allow stale snapshot cache fills (existing revision ticket barrier remains).
Sticky cookies deliberately retain the general selection path, and upstream
request-count recycling is unchanged (default 25,000 per generation).
## Locally executed checks vs required checks
- **Executed locally:** scoped-cache/sendfile/hot-path *source-only* guards,
Python syntax, SQLite migration and upgrade preservation tests, selected JS
panel scripts and simulated editor tests. These do **not** prove Rust builds.
- **Prepared, NOT executed:** Rust unit tests for shared routing, single-member
LB capacity/health, passive ejection/recovery, atomic log fields, retained
sendfile, cache and protocol behavior.
- **Unmeasured:** 0.34.0 requests/sec, latency, CPU cost, memory and nginx gap.
Do not infer a throughput gain from fewer source-code locks/allocations.
## Build and acceptance
Run on the intended Linux builder with exactly the same compiler, dependencies,
release flags and workload as the 0.33.8 reference:
```bash
./dev.sh doctor
./dev.sh check
CARGO_INCREMENTAL=0 ./dev.sh test
CARGO_INCREMENTAL=0 cargo build --release --locked
python3 scripts/tests/proxy_hotpath_034_static_test.py
python3 scripts/tests/cache_scope_034_static_test.py
python3 scripts/tests/sendfile_034_static_test.py
python3 scripts/tests/dashboard_presets_sql_test.py
python3 scripts/tests/upgrade_performance_test.py
```
Next run `scripts/performance/regression.py`, `lb_regression.py`,
`transport_regression.py` and `concurrency_regression.py` against both binary
versions. After functional acceptance, run the paired
`scripts/performance/benchmark.py` suite against the unmodified baseline,
this candidate and nginx; use the instructions in
`scripts/performance/README.md` including separate CPU affinities.
Measure RPS/p95/p99, CPU microseconds per request, RSS, FDs, pool rotations,
health transitions, cache HIT ratio and logger drops. For each payload report
`(0.34.0 RPS / 0.33.8 RPS - 1)*100` and `0.34.0 RPS/nginx RPS*100` from real
medians. A source-only revision is **not production-accepted**.