Files
RustProxy/docs/PROXY_RPS_0.34.0.md
T
2026-10-18 06:13:42 +02:00

5.9 KiB

RustProxy 0.34.0: hot-path throughput revision

Status: uncompiled source candidate. This revision does not change the application version, public API, dashboard controls, cache policy or tuning defaults. It must not be labelled production-ready until the new Rust binary passes compile, unit tests, live regressions and paired performance comparisons.

Code changes and intended cost reductions

Focus Change Kept behavior / risk to verify
Per-request identity Draw a 256-bit nonce from the OS-seeded/reseeded thread-local CSPRNG instead of asking getrandom on every request. Preserve SHA-256 of nonce+monotonic sequence and the existing 64-hex ID format. IDs remain non-predictable. Check ID uniqueness and raw upstream headers.
Upstream HTTP request target Compile the validated scheme/authority http::Uri once with each immutable backend; parse only the request path+query and rebuild using typed Uri::from_parts. Never accept a client-supplied authority, bypass DNS/address policies or change SNI. Test H1, H2, IPv6, query and percent-encoding.
Load balancing Do not clone the member ID string for an existing smooth-WRR scoreboard entry. Continue the previously introduced no-mutex single-member non-cookie path. Sticky-cookie modes, capacity limits, retry exclusions, health and drain remain unchanged.
Active health Use already-compiled Arc<HealthCheck> when dispatching probes, avoiding a clone of its path/headers for each scheduled probe. Same 250-ms supervisor, timeout, enabled/claim gate and health state transitions.
Per-frame streaming Capture the leased backend once at first streamed request DATA (response already captured at wrapper construction). Do not take Exchange.backend mutex on every upload chunk. Request/response byte counters, mid-stream failures, idle timeouts and lease lifetime remain active.
Pool recycling Preserve exact request-count and elapsed-time recycling checks per request, with the existing independent 250-ms maintenance cycle. The pool factory/connection policy is unchanged. Exact lifecycle semantics are more important than saving one cheap clock read; tune idle/age limits only after profiling.
Log history Move completed LogEntry directly into bounded history when there are no live viewers or enabled external sinks, instead of deeply cloning its strings. Continue cloning and delivering to live viewers/sinks when enabled. Same JSON fields, history size, drop counters, file/Loki/Logstash forwarding.
Route/HTTP instrumentation Remove redundant route-ID mutex/write in forwarding and collapse H1/H2 version tallying into one branch. Route is recorded once before forwarding; H1/H2 counters remain.

These historical changes build on the previous 0.34.0 route-Arc, single-backend LB, conditional retry/fallback-header cloning, atomic exchange flags and cache HOT LRU changes. There are no new UI toggles. This earlier revision retained max_idle_per_host 4 and pool_recycle_requests 25,000. The subsequent DEV 1 KiB revision changes only the default idle limit to 64, based on live configuration A/B with the old binary (not source A/B); see docs/PROXY_1KB_HOTPATH_DEV_0.34.0.md. sendfile: auto remains opt-in and applies only to eligible Linux plaintext H1 static WWW responses, not reverse proxy or TLS/H2/H3.

Cache transform/query policy

An enabled bypass_query is a deliberate policy: /theme.css?v=... is a BYPASS even when the origin sends Cache-Control: public. Turning the bypass off permits a transformed CSS object to follow MISS -> HIT and appear in the cache dashboard. An existing transformed HOT row with hit count and TTL is positive evidence of this. This throughput revision does not modify the cache eligibility logic or discard Age/ETag/Cache-Control headers.

Verification already possible here

  • Old/reproducible reference executable only: 110 passed, 0 failed, 1 skipped (compression.codec.zstd skipped because the optional decoder was missing), from live proxy/policy/cache/transform loopback regression. This does not exercise the newly modified Rust source.
  • Old/reproducible reference executable only: query bypass enabled gives BYPASS -> BYPASS, disabled gives MISS -> HIT and a transformed representation; the older Age regression is also reproducible on this old executable.
  • Source-only invariants: scripts/tests/rps_hotpath_034_static_test.py plus existing route/cache/sendfile checks. SQL migration and upgrade scripts pass.
  • Not performed: Rust compilation or newly added Rust unit tests, live behavior of the optimized binary, HTTP/2 live TLS, comparative RPS, CPU profiling and long-duration memory/health soak. The environment does not include cargo, rustc or wrk. No post-change RPS gain is claimed.

Acceptance commands on a Rust-capable Linux host

./dev.sh check
CARGO_INCREMENTAL=0 ./dev.sh test
CARGO_INCREMENTAL=0 cargo build --release --locked
python3 scripts/tests/rps_hotpath_034_static_test.py
python3 scripts/tests/cache_age_transform_034_live.py \
  --binary "$(realpath target/release/rust-proxy)" \
  --output /tmp/rustproxy034-cache-after
python3 scripts/performance/regression.py \
  --binary optimized="$(realpath target/release/rust-proxy)" \
  --out /tmp/rustproxy034-http-regression

Run scripts/performance/benchmark.py from the documented reproducible before/after/nginx command in scripts/performance/README.md. Compare the unchanged old 0.34.0 binary with the newly compiled source, not a baseline with different feature flags. Record RPS at 1,040 B, 64 KiB, 1 MiB, p95/p99, CPU/request, RSS, connection counts, errors and exact response-body hashes. Use perf record -g -p <proxy-pid> during a stable request interval and inspect perf report --stdio to identify the next true bottleneck.

Do not interpret Python origin self-tests, source inspections, or speculative Amdahl models as measured RustProxy throughput.