Files
RustProxy/docs/RELEASE_0.34.0_CACHE_FIX_PL.md
T
2026-10-17 22:33:00 +02:00

6.7 KiB

RustProxy 0.34.0 — poprawki cache, transformacji i kontrola RPS

Status: zmodyfikowane źródła, niekompilowane lokalnie (brak cargo i rustc). Numer wersji: 0.34.0.

Co odtworzono na binarce użytkownika

Uruchomiono binarkę Linux ELF w izolowanej konfiguracji z lokalnym origin HTTP, z włączonym cache, transformacją CSS, max_ttl_seconds=86400, diagnostyką i API administracyjnym. HTTP/1.1 localhost, pełne GET, brak kontaktu z witryną produkcyjną.

Odpowiedź Pierwszy GET Drugi GET Liczba pobrań z origin
/normal.css MISS HIT 1
/aged.css MISS MISS 2
/br.css MISS HIT 1
/aged-br.css MISS MISS 2
/private.css MISS MISS 2
/no-store.css MISS MISS 2

Zwykły CSS i skompresowany Brotli dostają HIT. Warianty z Age: 1553483 mają MISS → MISS mimo Cache-Control: public, max-age=2592000. Przypadki private / no-store słusznie nie trafiają do cache. Zmiana keep-alive vhosta nie usuwała poprawnie zachowanego obiektu. expose_only_hits=true celowo ukrywa nagłówki na MISS.

Główna przyczyna i poprawka

W src/cache/policy/response.rs obowiązywał wzór ttl = min(origin_max_age, local_max_ttl) oraz remaining = ttl - corrected_age. To jest sprzeczne z zadaniem lokalnego limitu: świeżość w origin nadal trwa, ale CDN Age > local_max_ttl dawał sztuczne 0 sekund lokalnej świeżości.

Poprawiony wzór:

corrected_initial_age = max(apparent_age, upstream_age + response_delay)
remaining_origin_freshness = max(0, origin_max_age - corrected_initial_age)
remaining_local_freshness = min(remaining_origin_freshness, local_max_ttl)
entry_fresh_until_age = corrected_initial_age + remaining_local_freshness

Przykład z przesłanych nagłówków: wiek upstream 1 553 483 s = prawie 18 dni. Pierwotna świeżość 2 592 000 s (30 dni), więc pozostało około 12 dni w origin. Po naprawie RustProxy będzie mógł przechować świeżą odpowiedź przez lokalny limit (domyślnie 86 400 s = 1 dzień). Nagłówek Age nadal będzie około 1,55 mln sekund i będzie rósł na HIT — to poprawne.

Age nie wynika z Last-Modified: 2016. Najczęściej jest przekazany przez upstream/CDN, a stara data Date też mogłaby podnieść apparent_age. Rozróżnienie: Age = HTTP wiek całkowity; resident_age_seconds = pobyt w HOT/COLD.

HOT RPS i panel

  1. HOT HIT nie wyjmuje już i nie wkłada od nowa wpisu oraz indeksu Vary, tylko aktualizuje licznik HIT i kolejność LRU w miejscu. Zmiana ma zmniejszyć alokacje i krytyczną sekcję; zysk RPS jeszcze niezmierzony.
  2. Panel Cache ma osobne kolumny Age i Czas w RustProxy. API dashboard.objects[] dodaje resident_age_seconds także dla COLD. Pozostałe nazwy pól nie zostały zmienione.
  3. Licznik x-cache-hits dotyczy konkretnego aktualnego wpisu. Gdy obiekt zostanie wyparte z HOT (limit wpisów/pamięć), usunięty lub zastąpiony po MISS, licznik restartuje. W próbce użytkownika TTL wynosił około 604 tys. s (7 dni), więc późniejszy MISS po ~4 minutach nie wynikał z normalnego wygaśnięcia TTL. Konkretnej przyczyny epizodu nie można ustalić bez trendów evictions, purges, hot_demotions, cold_hits, kluczy/Vary oraz zmian konfiguracji.
  4. Brak x-cache na MISS jest oczekiwany, gdy włączono nagłówki diagnostyczne tylko na HIT. Brak wpisu w API może mieć inne przyczyny (np. cache-control private, no-store, brak polityki origin, limit obiektu) i nie należy ich obchodzić na siłę.
  5. Nie zmieniano uprawnień, private/no-store, kluczy Vary, TTL po stronie origin ani zasad selektywnej invalidacji.

Wynik symulacji TTL

Wykonano 100 000 deterministycznych scenariuszy. Dla każdego sprawdzono: po naprawie lokalna świeżość nie przekracza local_max_ttl ani świeżości pozostałej w origin.

Scenariusz Stary pozostały TTL Po poprawce (symulacja)
Age = 1 553 483, local cap 1 dzień 0 s 86 400 s
Age = 1 553 483, local cap 7 dni 0 s 604 800 s
Origin kończy świeżość za 10 s 0 s 10 s
Origin jest już nieświeży 0 s 0 s

W symulacji 33 387 / 100 000 losowych przypadków stara polityka błędnie dawała zero zamiast dodatniego TTL. To nie jest procent regresji w realnym ruchu, a wynik losowania parametrów testowych.

Nginx — rzeczywiste pomiary starej binarki

Archiwalne wyniki samej binarki rust-proxy 0.34.0 na tym środowisku (Linux, 4 vCPU, HTTP/1.1 loopback, ApacheBench, 64 połączenia, cache OFF, 3 powtórzenia), z nginx 1.26.3. Brak miarodajnego benchmarku nowych źródeł przed ponowną kompilacją.

Endpoint RustProxy RPS (mediana) nginx RPS (mediana) RustProxy / nginx
proxy 1 KiB 10,544 58,709 18.0%
proxy 64 KiB 7,893 17,358 45.5%
proxy 1 MiB 1,010 1,666 60.6%
www 1 KiB 11,984 71,318 16.8%
www 64 KiB 9,224 26,600 34.7%
www 1 MiB 1,264 1,098 115.2%

Ograniczenia porównania: ApacheBench może limitować klienta; wyniki nie reprezentują TLS/H2/H3 ani ruchu produkcyjnego. Nie wolno tych RPS przypisywać nowej rewizji.

Zestaw testów dla nowej kompilacji

CARGO_INCREMENTAL=0 cargo test --locked --lib
CARGO_INCREMENTAL=0 cargo build --release --locked
python3 scripts/tests/cache_age_policy_034_model.py
python3 scripts/tests/cache_age_transform_034_live.py --binary target/release/rust-proxy --output /tmp/cache-test-034
python3 scripts/tests/cache_scope_034_static_test.py
python3 scripts/tests/proxy_hotpath_034_static_test.py
python3 scripts/tests/sendfile_034_static_test.py

Do testów jednostkowych dodano Age, transformowane CSS/HOT, democję do COLD i odczyt COLD po restarcie, logikę LRU/HIT oraz kontrolę zakazów private/no-store. Test lokalny sprawdza CSS/Brotli, origin count, API, keep-alive config i ukryte nagłówki. Test po kompilacji bez przełącznika --expect-old-age-bug ma wykazać MISS → HIT dla Age/Brotli. Na starej binarce odtwarzanie regresji przechodzi z --expect-old-age-bug.

Kontrole wykonane na źródłach: źródłowe testy cache scope, proxy hotpath, sendfile, składnia JS, parsowanie tłumaczeń. Nie uruchomiono testów Rust ani benchmarków poprawionej binarki — środowisko nie ma cargo/rustc.

Następny pomiar po kompilacji

Porównać tę rewizję 0.34.0 z poprzednią 0.34.0 oraz nginx dla 1 KiB / 64 KiB / 1 MiB; osobno cache OFF, HOT HIT i transformacja/Brotli. Raportować RPS, p95/p99, procesor, RSS, nowe TCP, cache.evictions i cache.purges; nie modyfikować ustawień cache podczas benchmarku.

Uwaga: curl -I -X GET miesza zachowanie HEAD i GET; do testów reprezentacji zalecane curl -sS -D - -o /dev/null URL.