Velocity-Antwort-Cache
Diese Seite richtet sich an Administratoren, die öffentliche Seiten mit Velocity ausliefern und sie in einem Bruchteil
einer Millisekunde beantworten möchten. Der Antwort-Cache behält gerenderte öffentliche Seiten und beantwortet
wiederholte Anfragen innerhalb des Serverprozesses, bevor ein Worker gewählt wird, sodass ein Treffer überhaupt keinen
Worker kostet. Er verhält sich wie ein kleiner Reverse Proxy: bedingte Anfragen (304), ETag, Age,
stale-while-revalidate, negatives Caching, komprimierte Speicherung und Invalidierung durch eine einzige berührte Datei.
Gilt für Exponential Velocity 0.0.4.x.
Eine zwischengespeicherte öffentliche Seite wird mit etwa 0,2 ms CPU ausgeliefert (gemessen auf einem Host mit 12 Kernen: eine Startseite über TLS mit gzip, etwa 2.950 Seiten pro Sekunde von einem Server, 11.985 von vier Servern auf einem Port). Das Rendern derselben Seite dauert Hunderte von Millisekunden. Eine stark besuchte Seite schickt nie alle Besucher gleichzeitig zu PHP, denn eine Anfrage erneuert eine abgelaufene Seite, während die anderen aus der alten Kopie beantwortet werden.
Einschalten
Der Cache ist aus, bis eine Einstellung enabled: true sagt. Seit Release 0.0.4.39 bedeutet keine
Cache-Einstellung auch keinen Cache. (Davor war der eingebaute Standard eingeschaltet, und das Deaktivieren des
Cache-Moduls hielt ihn nicht auf.)
In einer Site-Datei oder einem Modul wie
mods-available/cache.conf:{ "Q": { "web": { "cache": { "enabled": true, "dir": "/var/cache/qbix/example.com" } } } }Mit einem Konfigurationsverzeichnis schaltet
qbixctl enmod cacheihn beim nächsten Neustart ein undqbixctl dismod cacheaus. Ein Modul, das nurdiroderdefaultTtlsetzt, schaltet ihn nicht ein. Die Site-Datei (--config) wird zuletzt gelesen, sodassenabled: falsedort über ein Modul gewinnt; eine im Control Panel gespeicherte Einstellung gewinnt über beide.Lassen Sie die Anwendung sagen, wie lange eine Seite leben darf:
Q_Response::header('Cache-Control: public, max-age=300'); echo renderFeed();Starten Sie den Server neu oder laden Sie ihn neu, damit er die Einstellung übernimmt.
Prüfen Sie: Fragen Sie dieselbe öffentliche Seite zweimal an.
curl -sI https://example.com/ | grep -iE 'x-cache|age'Die zweite Antwort trägt
X-Cache: HITund einenAge-Header.
Was behalten wird
Eine Antwort wird nur gespeichert, wenn alles Folgende zutrifft:
- die Anfrage ist ein
GETauf einen Pfad, der nicht dem Server selbst gehört (/Q/...und/.well-known/...werden nie zwischengespeichert); - der Status ist
200, oder404/410, wennnegativeTtlgesetzt ist; - die Anfrage trägt keinen
Authorization-Header und keines derskip.cookies; - die Antwort setzt kein Cookie;
Cache-Controlsagt wederno-storenochprivate.
Der Schlüssel besteht aus Host, Pfad, Query-String und der Kodierung, in der der Inhalt gespeichert ist (gzip für
Clients, die es akzeptieren). Brotli- und gzip-Clients teilen sich einen Eintrag. Ein q=0 in Accept-Encoding zählt
als "nicht akzeptiert".
Das eigene Cache-Control: no-cache eines Besuchers umgeht den Cache nicht, sodass das Drücken von Neu laden den
Server nicht dazu bringen kann, jede Seite erneut zu rendern. Ein Cache-Warmer sendet stattdessen den Header
x-cache-refresh.
Die Lebensdauer ist s-maxage, sonst max-age, sonst defaultTtl (Standard 0, was nichts speichert).
Einträge liegen, sofern verwendbar, für kleine Einträge in APCu und als eine Datei pro Seite auf der Festplatte
unterhalb von dir, in einem zweistufigen Verzeichnis.
Nach einem Deployment alles invalidieren: der Generationsmarker
Ein geändertes Template oder Stylesheet ist für einen Cache unsichtbar, der Seiten danach beurteilt, was die Anwendung sagt. Berühren Sie nach einem Deployment den Marker:
touch /var/cache/qbix/example.com/.generation
qbixconsole cache:clearNur der Änderungszeitpunkt der Datei zählt. Jeder Eintrag, der zu oder vor diesem Zeitpunkt gespeichert wurde, wird als
Fehltreffer behandelt und bei seiner nächsten Anfrage ersetzt. Jeder Prozess liest den Marker höchstens einmal pro
Sekunde, sodass jeder Worker und jeder andere Server, der die Datei teilt, ihn innerhalb einer Sekunde sieht. Aus
Exponential heraus tut exp:velocity cache clear dasselbe, und exp:velocity deploy ruft es zuletzt auf
(Velocity-Engines).
Ablesen: Header und Zustand
| Header | Wann |
|---|---|
X-Cache: HIT | Aus dem Cache ausgeliefert |
X-Cache: STALE | Aus einer abgelaufenen Kopie ausgeliefert, während eine neue gerendert wird |
Age | Sekunden seit dem Speichern des Eintrags |
ETag | Bei jeder gespeicherten Seite |
/Q/health (vollständige Zahlen erfordern Admin-Zugriff) meldet hits, misses, hitRate, stale,
hitsFrom.index|memory|apcu|disk, memory.* und apcu.*. Überwiegend disk bei eingeschaltetem APCu bedeutet, dass
APCu seinen Teil nicht leistet: Prüfen Sie apc.enable_cli.
Einstellungen
Alle unter Q.web.cache.
| Konfigurationsschlüssel | Standard | Bedeutung |
|---|---|---|
enabled | false | Den Cache einschalten |
dir | <app>/files/cache/reverse | Wo Einträge und der Marker liegen |
defaultTtl | 0 | Lebensdauer in Sekunden für eine Antwort, die keine angibt |
skip.cookies | ["Q_sid", "PHPSESSID"] | Cookie-Namen (nach Präfix verglichen), die eine Anfrage als persönlich kennzeichnen |
staleWhileRevalidate | 0 | Sekunden, die eine abgelaufene Seite noch ausgeliefert wird, während eine Anfrage eine neue Kopie rendert |
revalidateLockSeconds | 30 | Nach dieser Zeit gilt eine Anfrage, die eine veraltete Seite erneuert, als verschwunden |
negativeTtl | 0 | Sekunden, die 404- und 410-Antworten behalten werden |
refreshHeader | x-cache-refresh | Anfrage-Header, der die Seite erneut rendert und speichert |
generationFile | <dir>/.generation | Der Generationsmarker |
apcu.enabled | wenn APCu verwendbar ist | Kleine Einträge zusätzlich zur Festplatte in APCu halten (erfordert apc.enable_cli=1 unter der CLI) |
apcu.maxSize | 65536 | Größter Inhalt in Bytes, der in APCu gehalten wird |
memory.maxEntries | 0 | Seiten, die im eigenen Speicher des Servers vor APCu gehalten werden; 0 schaltet die Schicht aus |
memory.maxBytes | 33554432 | Höchstzahl an Bytes von Inhalten, die im Speicher gehalten werden |
memory.maxEntrySize | 65536 | Größter Inhalt, der im Speicher gehalten wird |
minifyHtml | false | Leerraum in zwischengespeichertem HTML zusammenfassen |
middleOut | false | Gespeicherte Inhalte gegen ein gemeinsames Wörterbuch komprimieren (zuerst messen) |
fileMode | 0666 abzüglich der umask | Modus der Eintragsdateien |
dirMode | 0755 | Modus der Cache-Verzeichnisse |
sweep.every | 300 | Sekunden zwischen Bereinigungen abgelaufener Dateien; 0 schaltet die Bereinigung aus |
sweep.budget | 2000 | Höchstzahl an Dateien, die eine Bereinigung betrachtet |
sweep.maxAge | 0 | Auch Dateien entfernen, die älter als so viele Sekunden sind |
pauseFile | keiner | Solange diese Datei existiert, antworten weder dieser Cache noch der Cache der Anwendung (Wartungsfenster) |
Über das Control Panel verwenden
Der Tab Cache des Panels (/Q/panel) bietet Schalter für den Cache, APCu und die Speicherschicht, die aktuelle
Trefferquote, Voreinstellungen für die Lebensdauern, Alles leeren, Löschen nach URL oder Muster, das Vorwärmen einer
Seite und einen Browser über die gespeicherten Seiten. Dort gespeicherte Einstellungen liegen im Speicher des Panels
und gewinnen über die Datei. Nur zehn Einstellungen werden von dort übernommen: enabled, defaultTtl,
staleWhileRevalidate, negativeTtl, skip.cookies, apcu.enabled, apcu.maxSize, memory.maxEntries,
memory.maxBytes, minifyHtml. Die API liegt unter /Q/api/cache.
Der eigene Cache einer Anwendung
Der Antwort-Cache überspringt Anfragen mit einem Sitzungs-Cookie, weil er Besucher nicht auseinanderhalten kann. Eine Anwendung, die gerenderte Seiten pro Besucher oder Rolle behält, kann zuerst gefragt werden, im Serverprozess, sodass ein Treffer nie einen Worker weckt:
{ "Q": { "web": { "appCache": {
"file": "/path/to/app/lib/PageCache.php",
"class": "PageCache",
"dir": "/path/to/app/var/page-cache"
} } } }classbenötigt ein statischesfromDir($dir)und einserve(array $request), das bei einem Treffer[status, headers, body]zurückgibt und sonstnull.- Die Anfrage trägt
scheme,host,uri,method,cookies,acceptEncoding,ifNoneMatchund (seit 0.0.4.35)headersundport. - Eine Anfrage mit einem Sitzungs-Cookie geht nur an den Cache der Anwendung. Jede andere Anfrage wird zuerst vom Antwort-Cache beantwortet und bei einem Fehltreffer vom Cache der Anwendung, und diese Antwort wird im Antwort-Cache behalten.
- Da der Antwort-Cache dann zuerst antwortet, richten Sie
Q.web.cache.generationFileauf eine Datei, die jede Bereinigung der Anwendung neu schreibt (exp:velocityvon Exponential verwendet die Statusdatei des HTTP-Caches).
Grenzen und Fallstricke
- Personalisierte Seiten nicht zwischenspeichern. Alles mit einem Cookie,
Authorization,privateoderno-storewird übersprungen; sorgen Sie dafür, dass das in Ihren Templates so bleibt. - Aktualisierung über 0.0.4.29 hinweg: Zwischengespeicherte Seiten werden unter der Kodierung abgelegt, in der sie gespeichert sind, sodass die erste Anfrage jeder Seite nach der Aktualisierung neu gerendert wird.
- Aktualisierung auf 0.0.4.39: Eine Installation, die sich auf den alten Standard verließ und nirgends
enabledsetzt, hört auf zu cachen; fügen Sie{"Q":{"web":{"cache":{"enabled":true}}}}hinzu. - APCu unter der CLI benötigt
apc.enable_cli=1; der Server weist beim Start darauf hin, wenn es aus ist. - Die Speicherschicht spart bei großen Seiten etwa 12 Prozent CPU pro Treffer und bei kleinen nichts; messen Sie auf Ihrer eigenen Site.
Vollständige Schritte zur Aktualisierung: Hinweise zur Aktualisierung der Velocity-Engine.
Verwandte Seiten
- Control Panel (Tab Cache), statische Dateien und Bilder (Datei-Caching), Scheduler (die Cache-Bereinigung), Velocity: Exponential in einem Webserver mit persistenten Workern betreiben
- Spezifikationen: Worker-Pool, Engine-Einstellungen, HTTP/2 und Sicherheit (was nie zwischengespeichert wird)
- Caching in Exponential: HTTP-Cache, der rollenbewusste HTTP-Cache, der Antwort-Cache und wie man dem Netzwerk aus dem Weg geht, Velocity-Engines
- Changelog: Exponential-Velocity-Engine
- Chronik: 22. September, 25. bis 30. September
Werden Sie Exponential-Partner
Partner teilen ihre Informationen, stellen Mittel bereit, geben Beiträge zurück und entwickeln die Produkte mit uns, und so wächst Exponential. Eine Partner-Website und ein Dashboard sind für Mitte 2027 geplant: Werden Sie noch heute Partner, damit wir schneller wachsen und neue Funktionen früher liefern.