v0.34.0_1
This commit is contained in:
1 parent
9cfc4588cc
commit
f20c8da718
25 files changed
+694
-117
No files matched your search
@@ -0,0 +1,132 @@
|
||||
# RustProxy 0.34.0 DEV — 1 KiB lock contention follow-up
|
||||
|
||||
## Goal and baseline
|
||||
|
||||
**Priority 1: reverse proxy, HTTP/1.1 keep-alive, uncompressed 1,040-byte
|
||||
responses, cache OFF.** Aiming for approximately 100,000 RPS and at least 80%
|
||||
of nginx under the same pinned-CPU benchmark. Priority 2: local static WWW,
|
||||
measured separately. No feature removals and **no version bump**.
|
||||
|
||||
The user supplied a **new executable** (SHA-256
|
||||
`1a84c58b20945bba9fdd1bc1a44d9e9d6ac7659d714343a46a1a8511a78331fa`,
|
||||
`rust-proxy 0.34.0`), apparently built from the prior DEV revision. It passed
|
||||
151 actual black-box HTTP tests with 0 failures and 1 skipped optional zstd
|
||||
decoder. This runtime coverage belongs to the **supplied executable only**,
|
||||
not to the freshly edited source below. Neither `cargo` nor `rustc` is
|
||||
available in the editing environment; the new revision has NOT been compiled.
|
||||
|
||||
## Modified source
|
||||
|
||||
### `Cache::record` and `Cache::record_reason`
|
||||
|
||||
Before, every HIT, MISS and BYPASS acquired the same `Store` mutex used by the
|
||||
HOT object store, exact LRU and cache inventory. With cache disabled, a 1 KiB
|
||||
request still contested that mutex to increment `cache_disabled`.
|
||||
|
||||
`src/cache/stats.rs` now holds bounded per-(scope,domain) statistics separately:
|
||||
|
||||
- An `ArcSwap`-published immutable, borrowed-lookup BTreeMap of domain handles.
|
||||
**The normal path does not lock or allocate**, even for BYPASS. New domains
|
||||
alone use a registration mutex and a copy-on-first-visit registry update.
|
||||
- Atomic counts for HIT, MISS, BYPASS, stored objects and saved body bytes.
|
||||
The common static reasons (`cache_disabled`, `cache_hit`, `cache_miss`,
|
||||
`request_cookie`) use direct atomic counters. Other reason names use another
|
||||
immutable published index and atomic counters; they are registered once.
|
||||
- Hard cardinality remains **4096 (scope, domain) pairs**. When full, new
|
||||
unregistered domains are skipped as before. Scope purge preserves stats.
|
||||
Only a revision-bearing global purge resets the per-domain registry.
|
||||
- The dashboard still exposes the same `DomainCounters`, reason strings,
|
||||
saved byte counts, ratio and per-vhost/object views. Counter snapshots are
|
||||
quiescent-exact, but under concurrent requests individual fields can reflect
|
||||
slightly different instants, consistent with other atomic metrics.
|
||||
- HOT object and COLD representation/LRU access, barriers, memory accounting,
|
||||
cache statuses, hit policy, retry and backend security paths are unchanged.
|
||||
|
||||
Trade-offs: a first-visit registration copies the bounded domain index and
|
||||
allocates one counter set; this is not an adaptive, unbounded cache. The hot
|
||||
path's ArcSwap guard and lookup still cost CPU. Measure that cost in profiles;
|
||||
compare under high-cardinality traffic to identify any excessive registration
|
||||
cost before production acceptance.
|
||||
|
||||
### Traffic analytics queue saturation
|
||||
|
||||
Previously `Exchange::drop` cloned the vhost, route, method, path, IP, user
|
||||
agent and country before trying to enqueue the `Sample`. If the bounded
|
||||
2,048-element MPSC queue was full, all those clones were discarded.
|
||||
|
||||
`Analytics::push_lazy` now acquires the same bounded Tokio queue permit with
|
||||
`try_reserve` first and creates the sample only after a successful reservation.
|
||||
Rejections increment `queue_dropped` exactly as before. Neither the analytics
|
||||
worker, counters/top lists, reset behavior nor request log path is removed.
|
||||
This improves allocation costs **on overflow** but does not turn dropped
|
||||
analytics into delivered samples; monitor the existing drop counter.
|
||||
|
||||
### Per-vhost duration histogram atomics
|
||||
|
||||
Previously `VhostMetrics::complete` incremented every cumulative latency bucket
|
||||
whose threshold covered the observation and the `+Inf` bucket. For an ordinary
|
||||
short response this meant **11 shared atomic RMWs** for the histogram alone,
|
||||
on top of existing exchange/status/byte/latency metrics.
|
||||
|
||||
It now increments **exactly one exclusive bucket** chosen from the same 10
|
||||
latency boundaries. Both the regular vhost and Docker-vhost Prometheus exporters
|
||||
compute the original cumulative `le` buckets, `+Inf` and `_count` from the 11
|
||||
exclusive buckets **at scrape time**. The metric names, labels, boundaries,
|
||||
body-lifetime timing and measurement collection remain intact. The cumulative
|
||||
snapshot may be concurrent with request completions, as before. Added boundary
|
||||
unit tests for exact thresholds and long-duration `+Inf`.
|
||||
|
||||
This is source-only: neither the throughput benefit nor compiled Rust behavior
|
||||
has been verified in the editing environment. Review exporter parity and
|
||||
under-load histogram correctness on the newly compiled executable.
|
||||
|
||||
## Verification and untested claims
|
||||
|
||||
- PASS: source preflight, cache/HOT/LB/RPS/histogram/static source guards and <=500-line
|
||||
production Rust modules.
|
||||
- PASS: SQLite migration + preset constraints, upgrade/lock and source
|
||||
replacement tests.
|
||||
- PASS: compiled user-supplied binary: 151 real HTTP checks, 0 failed,
|
||||
1 optional zstd skip. This binary predates the source changes above.
|
||||
- NOT RUN: Rust compile, Rust unit tests, native regressions or RPS after
|
||||
rebuilding the new source. No numerical speedup attributed to this patch.
|
||||
- Current diagnostic A/B on the user-supplied binary may use
|
||||
`scripts/performance/ab_1kb_dev.py` and must remain labelled *old vs already
|
||||
supplied binary*, **not** old vs newly edited source. The `wrk` 30 s x 7
|
||||
pinned-CPU benchmark remains the production acceptance gate.
|
||||
|
||||
## Repeat on a compiler-enabled benchmark host
|
||||
|
||||
```bash
|
||||
./dev.sh doctor
|
||||
./dev.sh check
|
||||
CARGO_INCREMENTAL=0 ./dev.sh test
|
||||
CARGO_INCREMENTAL=0 cargo build --release --locked
|
||||
python3 scripts/performance/regression.py \
|
||||
--binary previous=/absolute/path/to/supplied-rust-proxy \
|
||||
--binary edited="$(realpath target/release/rust-proxy)" \
|
||||
--out /tmp/rustproxy034-counter-http
|
||||
python3 scripts/performance/lb_regression.py \
|
||||
--binary previous=/absolute/path/to/supplied-rust-proxy \
|
||||
--binary edited="$(realpath target/release/rust-proxy)" \
|
||||
--out /tmp/rustproxy034-counter-lb
|
||||
python3 scripts/performance/transport_regression.py \
|
||||
--binary previous=/absolute/path/to/supplied-rust-proxy \
|
||||
--binary edited="$(realpath target/release/rust-proxy)" \
|
||||
--out /tmp/rustproxy034-counter-transport
|
||||
python3 scripts/performance/benchmark.py \
|
||||
--binary previous=/absolute/path/to/supplied-rust-proxy \
|
||||
--binary edited="$(realpath target/release/rust-proxy)" \
|
||||
--nginx /usr/sbin/nginx --wrk /absolute/path/to/wrk \
|
||||
--out /tmp/rustproxy034-counter-benchmark \
|
||||
--modes proxy --sizes small --concurrency 16,64,128 \
|
||||
--duration 30 --warmup 5 --repeats 7
|
||||
```
|
||||
|
||||
Explicitly set `max_idle_per_host=64` on **both** before/after vhosts, with the
|
||||
same TLS/H1/H2/health/cache/logging/settings. Verify 1,040 bytes and SHA-256,
|
||||
no failures, latency percentiles, per-request CPU, RSS, file descriptors,
|
||||
backend connects and all log/traffic drop counters. Test concurrent global
|
||||
purges and per-vhost purges during traffic and verify the stats reset behavior
|
||||
and cache HIT/MISS/BYPASS/reason distribution. Run long soaks and both cold/HOT
|
||||
cache tests. The 100k RPS / nginx 80% goal is still **OPEN**.
|
||||
@@ -9,6 +9,21 @@ compiled**, the new Rust tests were **not executed**, and no 0.34.0 RustProxy
|
||||
binary or live throughput figures are supplied. Source inspection and simulated
|
||||
UI/cache tests do not close the runtime acceptance gate.
|
||||
|
||||
## DEV 1 KiB counters follow-up (source remains uncompiled)
|
||||
|
||||
The newly supplied binary `rust-proxy(1)` identifies as 0.34.0 and has
|
||||
SHA-256 `1a84c58b20945bba9fdd1bc1a44d9e9d6ac7659d714343a46a1a8511a78331fa`.
|
||||
It completed **151 passing real HTTP tests, 0 failures, 1 optional zstd
|
||||
skip**. These tests were run on the supplied binary, not on the subsequently
|
||||
modified source. The latest source moves per-domain cache statistics outside
|
||||
HOT store mutexes and lazily allocates analytics samples only after a queue
|
||||
permit is available. Histogram completion now increments one exclusive
|
||||
latency bin instead of up to 11 cumulative bins; both Prometheus exporters
|
||||
convert them to the same cumulative format at scrape time. Static
|
||||
source/SQL/upgrade checks pass; **Rust compile,
|
||||
Rust unit tests and live new-source RPS remain OPEN**. See
|
||||
`docs/PROXY_1KB_COUNTERS_DEV_0.34.0.md` and the separate evidence archive.
|
||||
|
||||
## DEV 1 KiB reverse-proxy follow-up (October 2026; source only)
|
||||
|
||||
The supplied **old executable** passed loopback HTTP/1.1 1,040-byte content
|
||||
|
||||
Reference in new issue
Block a user