78 lines
5.7 KiB
Markdown
78 lines
5.7 KiB
Markdown
# 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 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. Pool defaults remain `max_idle_per_host`
|
|
4 and `pool_recycle_requests` 25,000; tune these only in separately labelled
|
|
trials. `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
|
|
|
|
```bash
|
|
./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.
|