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

4.6 KiB

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:

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