Development

Documentation/de_DE/book/1.0/12-Caching

You must first sign up to be able to contribute.

ARBEITSENTWURF ROHÜBERSETZUNG / TRANSLATION WORKING DRAFT
Originaldokument: http://svn.symfony-project.com/doc/branches/1.1/book/12-Caching.txt, Version 8533 vom 2008-04-05
Übersetzungsfortschritt: 100%
Übersetzung: JK
Korrekturfortschritt: 0%

Kapitel 12 - Caching

Ein Weg zur Beschleunigung von Anwendungen ist, ganze Teile erzeugten HTML-Codes oder sogar ganze Seiten für zukünftige Anfragen zu speichern. Diese Technik ist als "Caching" ("Puffer") bekannt und kann sowohl serverseitig als auch clientseitig stattfinden.

Symfony verfügt über ein flexibles, serverseitiges Cachingsystem. Es ermöglicht, die ganze HTML-Antwort, das Ergebnis einer Aktion, eines Partials oder eines Template-Fragments in Dateien zu speichern und benutzt dafür ein sehr intuitives Setup auf Basis von YAML-Dateien. Wenn sich die zugrunde liegenden Daten ändern, können Sie einfach gezielt Teile des Caches von der Kommandozeile oder durch spezielle Action-Methoden löschen. Symfony bietet Ihnen auch einen einfachen Weg, das clientseite Caching über HTTP 1.1-Header zu kontrollieren. Dieses Kapitel behandelt all diese Themen und gibt Ihnen einige Tipps, wie Sie ermitteln können, wie gut Ihre Anwendung durch Caching optimiert wird.

Antworten cachen

Das Prinzip beim Cachen von HTML ist einfach: Der HTML-Code, der infolge eines Request zum Benutzer geschickt wird, kann in Teilen oder ganz für ähnliche Requests wiederverwendet werden. Dieser HTML-Code wird an einem speziellen Ort aufbewahrt (bei symfony ist das das Verzeichnis cache/), wo der Frontcontroller nachsieht, bevor er eine Action ausführt. Wenn eine gecachte Version vorhanden ist, wird sie ohne Ausführung der Action ausgegeben, was die Verarbeitung drastisch beschleunigt. Wenn keine gecachte Version vorhanden ist, wird die Action ausgeführt, und die Antwort (also der View) wird im Cache-Verzeichnis für zukünftige Requests gespeichert.

Da alle Seiten dynamisch erzeugte Informationen enthalten könnten, ist der HTML-Cache per Default ausgeschaltet. Es obliegt also dem Administrator der Site, es einzuschalten, um die Performance zu verbessern.

Symfony kann drei verschiedene Arten von HTML-Caching:

  • Cachen einer Action (mit oder ohne Layout)
  • Cachen eines Partials, einer Komponente oder eines Komponentenslots
  • Cachen eines Templatefragments

Die ersten beiden Arten werden über YAML-Dateien konfiguriert. Das Cachen von Templatefragmenten wird gesteuert, indem im Template Helper-Funktionen aufgerufen werden.

Globale Cache-Einstellungen

Für jede Anwendung eines Projekts und für jede Umgebung kann der HTML-Cachingmechanismus über die Einstellung cache in der Datei settings.yml ein- oder ausgeschaltet (Voreinstellung) werden. Listing 12-1 zeigt, wie der Cache aktiviert wird.

Listing 12-1 - Aktivieren des Caches, in frontend/config/settings.yml

dev:
  .settings:
    cache:                  on

Cachen einer Action

Actions, die statische Informationen anzeigen (also nicht von Daten aus einer Datenbank oder der Session abhängen), oder Actions, die Informationen aus der Datenbank lesen, ohne sie zu verändern (typischerweise GET-Requests) eigenen sich oft ideal zum Cachen. Abbildung 12-1 zeigt, welche Elemente einer Seite in diesem Fall gecachet werden: entweder das Ergebnis der Action (das Template) oder das Ergebnis zusammen mit dem Layout.

Abbildung 12-1 - Cachen einer Action

Cachen einer Action

Betrachen wir beispielsweise eine Action user/list, die eine Liste aller Benutzer einer Website zurückgibt. Solange keine Benutzerdaten verändert, hinzugefügt oder entfernt werden (diese Punkte werden wir später im Abschnitt "Elemente aus dem Cache entfernen" besprechen), zeigt die Liste immer die gleiche Information und ist deshalb ein guter Kandidat für unseren Cache.

Aktivierung und Einstellungen des Caches sind für jede Action in einer Datei namens cache.yml im Verzeichnis config/ des Moduls gespeichert. Listing 12-2 zeigt ein Beispiel.

Listing 12-2 - Den Cache für eine Action aktivieren, in frontend/modules/user/config/cache.yml

list:
  enabled:     on
  with_layout: false   # Standardwert
  lifetime:    86400   # Standardwert

Mit dieser Beispielkonfiguration wurde festgelegt, dass der Cache für die Action list aktiv ist und das Layout nicht mitgespeichert wird (dies ist das Standardverhalten). Dies bedeutet, dass das Layout (zusammen mit seinen Partials und Komponenten) trotzdem noch ausgeführt wird, selbst wenn eine gecachete Version der Action vorhanden ist. Wenn with_layout auf true gesetzt ist, dann wird das Layout zusammen mit der Action gespeichert und nicht erneut ausgeführt.

Um die Cache-Einstellungen zu testen, rufen Sie die Action in der Entwicklungs-Umgebung (dev) in Ihrem Browser auf.

http://myapp.example.com/frontend_dev.php/user/list

Sie werden auf der Seite einen Rahmen um den Bereich der Action bemerkten. Beim ersten Aufruf hat der Bereich eine blaue Kopfzeile, welche anzeigt, dass die Daten nicht aus dem Cache kommen. Wenn Sie die Seite erneut laden, ist die Kopfzeile des Bereichs gelb, was bedeutet, dass die Daten jetzt aus dem Cache kommen (mit einer merkbar schnelleren Antwortzeit). Später in diesem Kapitel werden Sie noch mehr darüber lernen, wie Sie das Caching testen und überwachen.

NOTE Da Slots Teil des Templates sind, werden beim Cachen einer Action auch die Inhalte der Slots im entsprechenden Template gespeichert. Somit funktioniert der Cache auch für Slots.

Das Caching-System funktionert auch bei Seiten, die von Parametern abhängen. So könnte z.B. das Modul user eine Action show enthalten, welche das Argument id zur Anzeige der Userdetails erwartet. Aktivieren Sie in der Datei cache.yml auch für diese Action den Cache, wie in Listing 12-3 gezeigt.

Um Ihre cache.yml etwas zu strukturieren, können Sie die Einstellungen, die auf alle Actions eines Moduls zutreffen, unterhalb des Schlüssels all: gruppieren, wie ebenfalls in Listing 12-3 zu sehen.

Listing 12-3 - Eine vollständige cache.yml-Datei, in frontend/modules/user/config/cache.yml

list:
  enabled:    on
show:
  enabled:    on

all:
  with_layout: false   # Standardwert
  lifetime:    86400   # Standardwert

Jetzt erzeugt jeder Aufruf der Action user/show mit einem anderen id-Argument einen neuen Eintrag im Cache. Also wird der Cache für diesen Aufruf:

http://myapp.example.com/user/show/id/12

ein anderer sein als der Cache für diesen:

http://myapp.example.com/user/show/id/25

ACHTUNG Actions, die mit der POST-Methode oder mit GET-Parametern aufgerufen werden, werden nicht gecachet.

Die Einstellung with_layout verdient noch ein paar Worte. Sie bestimmt letztlich, welche Art von Daten im Cache gespeichert werden. Für den Cache ohne Layout wird nur das Ergebniss der Template-Ausführung und die Action-Variablen gespeichert. Beim Cache mit Layout wird das gesamte Antwortobjekt gespeichert. Also ist das Cachen mit Layout noch schneller als ohne.

Wenn es die Funktionalität Ihrer Webanwendung zulässt (also wenn das Layout nicht auf Daten aus der Sitzung zugreift), sollten Sie sich für das Cachen mit Layout entscheiden. Meistens enthält das Layout allerdings dynamische Elemente (z.B. den Namen des angemeldeten Users), weshalb das Cachen der Action ohne Layout die üblichste Konfiguration ist. RSS-feeds, Popups und Seiten die nicht von Cookies abhängen können aber mit Layout gecachet werden.

Cachen von Partials, Komponenten und Komponentenslots

In Kapitel 7 wurde erklärt, wie Sie mit dem Helper include_partial() Codefragmente für mehrere Templates wiederverwenden können. Ein Partial ist genauso einfach zu cachen wie eine Action, und die Aktivierung des Caches funktioniert nach den gleichen Regeln, wie in Abbildung 12-2 gezeigt.

Abbildung 12-2 - Cachen von Partials, Komponenten und Komponentenslots

Cachen von Partials, Komponenten und Komponentenslots

Listing 12-4 zeigt, wie Sie die Datei cache.yml bearbeiten müssen, um den Cache für die Datei _mein_partial.php des Modules user einzuschalten. Beachten Sie, dass die Einstellung with_layout in diesem Fall sinnlos ist.

Listing 12-4 - Cachen eines Partials, in frontend/modules/user/config/cache.yml

_mein_partial:
  enabled:    on
list:
  enabled:    on
...

Ab jetzt wird kein PHP-Code mehr ausgeführt, wenn Templates dieses Partial verwendet. Statt dessen wird die gecachete Version verwendet.

[php]
<?php include_partial('user/mein_partial') ?>

Genau wie bei den Actions ist auch das Cachen von Partials von Bedeutung, wenn das Ergebnis des Partials von Parametern abhängen. Das Cachingsystem wird so viele verschiedene Versionen eines Templates speichern wie es verschiedene Werte der Parameter gibt.

[php]
<?php include_partial('user/mein_anderes_partial', array('foo' => 'bar')) ?>

TIP Der Action-Cache ist mächtiger als der Partial-Cache, denn wenn eine Action gecachet wird, wird das Template nicht einmal ausgeführt; wenn das Template Partials aufruft, werden diese Aufrufe nicht durchgeführt. Deshalb ist Partial-Caching nur dann nützlich, wenn Sie für die aufrufende Action keinen Cache verwenden, oder für Partials, die im Layout verwendet werden.

Ein kurzer Rückblick auf Kapitel 7: Eine Komponente ist eine Action "light", die auf einem Partial aufbaut; ein Komponenten-Slot ist eine Komponente, bei der die Action je nach aufrufender Action variiert. Diese zwei Arten der Einbindung ähneln Partials und unterstützen Caching auf die gleiche Weise. Wenn z.B. Ihr globales Layout eine Komponente namens tag mit include_component('general/tag') einbindet, um das aktuelle Datum anzuzeigen, schreiben Sie in cache.yml des Moduls general folgendes, um die Komponente zu cachen:

_tag:
  enabled: on

Wenn Sie eine Komponente oder ein Partial cachen, müssen Sie festlegen, ob Sie eine Version für alle aufrufenden Templates speichern oder eine Version für jedes. Der Standard ist, die Komponente unabhängig vom aufrufenden Template zu speichern. Kontextabhängige Komponenten, die z.B. einen unterschiedlichen Sidebar zu jeder Action anzeigen, sollten jedoch so oft gespeichert werden, wie es Templates gibt, die sie aufrufen. Das Caching-System kann diesen Fall berücksichtigen, vorausgesetzt, sie haben den Parameter contextual auf true gesetzt, wie hier gezeigt:

_tag:
  contextual: true
  enabled:   on

NOTE Globale Komponenten (also diejenigen im Verzeichnis templates/ der Applikation) können gecacht werden, wenn Sie ihre Cacheeinstellungen in cache.yml der Applikation speichern.

Cachen eines Templatefragments

Der Actioncache funktioniert nur bei einer Teilmenge der Actions. Bei anderen - also jenen, die Daten aktualisieren oder sessionabhängige Informationen im Template anzeigen - gibt es immer noch Verbesserungsmöglichkeiten beim Cache, aber auf andere Weise. Symfony stellt einen dritten Cachetyp zur Verfügung, der sich Templatefragmenten annimmt und direkt im Template angewendet wird. In diesem Modus wird die Action immer ausgeführt, und das Template teilt sich auf in Fragmente, die ausgeführt werden, und Fragmente im Cache, wie in Abbildgung 12-3 gezeigt.

Abbildung 12-3 - Cachen eines Templatefragments

Cachen eines Templatefragments

Nehmen wir an, Sie haben eine Liste mit Benutzern, und dazu einen Link auf den zuletzt aufgerufenen Benutzer, wobei diese Information dynamisch ist. Der Helper cache() legt die Teile des Templates fest, die in den Cache gehen können. Listing 12-5 zeigt die syntaktischen Details.

Listing 12-5 - Verwendung des cache()-Helfers, in frontend/modules/user/templates/listSuccess.php

[php]
<!-- Code wird jedes Mal ausgeführt -->
<?php echo link_to('Letzter aufgerufener Benutzer', 'user/show?id='.$last_accessed_user_id) ?>

<!-- Code wird gecacht -->
<?php if (!cache('benutzer')): ?>
  <?php foreach ($users as $user): ?>
    <?php echo $user->getName() ?>
  <?php endforeach; ?>
  <?php cache_save() ?>
<?php endif; ?>

Und so funktioniert es:

  • Wenn eine gecachte Version des Fragments 'users' vorhanden ist, wird sie verwendet, um den Code zwischen den Zeilen <?php if (!cache($eindeutiger_fragment_bezeichner)): ?> und <?php endif; ?> zu ersetzen.
  • Wenn nicht, wird der Code zwischen diesen Zeilen verarbeitet und im Cache unter dem eindeutigen Fragement-Bezeichner gespeichert.

Der Code, der nicht von diesen Zeilen eingeschlossen wird, wird stets ausgeführt und nicht gecachet.

ACHTUNG Für die Action (im Beispiel also list) dürfen Sie das Caching nicht aktiviert haben, da dies die Templateausführung komplett umgeht und somit die Angabe für das Fragment-Caching ignoriert.

Der Geschwindigkeitsgewinn beim Cachen von Templatefragmenten ist nicht so groß wie der des Actioncaches, da die Action immer ausgeführt, das Template teilweise verarbeitet und das Layout immer zum Dekorieren verwendet wird.

Sie können im gleichen Template weitere Fragmente definieren, vorausgesetzt, Sie geben jedem einen eindeutigen Namen, so dass das Cachesystem von Symfony sie hinterher wieder auffinden kann.

Wie auch bei Actions und Komponenten kann für gecachte Fragmente eine Lebensdauer in Sekunden angegeben werden, die dem cache()-Helfer als zweites Argument übergeben wird.

[php]
<?php if (!cache('benutzer', 43200)): ?>

Wenn dem Helfer kein Parameter übergeben wird, wird für den Cache die Standard-Lebensdauer (86400 Sekunden, bzw. ein Tag) verwendet.

TIP Ein anderer Weg, eine Action cachebar zu machen, ist, die veränderbaren Parameter in das Routingmuster der Action aufzunehmen. Wenn beispielsweise eine Seite den Namen des angemeldeten Benutzers anzeigt, kann sie nicht gecachet werden, solange die URL nicht den Nickname der Benutzer beinhaltet. Ein weiteres Beispiel sind internationalisierte Anendungen: Wenn Sie das Caching für eine Seite aktivieren wollen, die mehrere Übersetzungen hat, muss das Sprachkürzel irgendwie in das URL-Muster einfließen. Dieser Trick erhöht zwar die Anzahl der Seiten im Cache, kann aber eine große Hilfe sein, um interaktive Anwendungen deutlich zu beschleunigen.

Dynamische Konfigurieration des Caches

Die Datei cache.yml ist eine Möglichkeit, die Einstellungen des Caches festzulegen, ist allerdings sehr unflexibel. Sie können jedoch, wie in Symfony üblich, statt YAML reines PHP verwenden, was es Ihnen erlaubt, den Cache dynamisch zu konfigurieren.

Warum sollten Sie den Cache überhaupt dynamisch einstellen können? Ein gutes Beispiel ist eine Seite, die für authentifizierte Benutzer anders aussieht als für unangemeldete, deren URL jedoch die gleiche bleibt. Stellen Sie sich z.B. eine Seite article/show mit einem Ratingsystem für Artikel vor. Das Ratingsystem ist für unangemeldete Benutzer nicht aktiviert, statt dessen führen für sie die Links auf ein Loginformular. Diese Version der Seite kann gecachet werden. Bei angemeldeten Benutzern löst der Klick auf einen Ratinglink einen POST-Request aus und erzeugt ein neues Rating. Dafür muss der Cache abgeschaltet sein, so dass Symfony die Seite dynamisch aufbaut.

Der richtige Ort, um diese Cache-Einstellungen zu definieren, ist ein Filter, der vor dem sfCacheFilter ausgeführt wird. Tatsächlich ist der Cache nur ein Symfony-Filter, wie auch die Sicherheitsfunktionen. Um den Cache der Seite article/show nur zu aktivieren, wenn der User noch unauthentifiziert ist, erzeugen Sie einen conditionalCacheFilter im lib/-Verzeichnis Ihrer Anwendung, wie in Listing 12-6 gezeigt.

Listing 12-6 - Dynamische Konfigurieration des Caches mit PHP, in frontend/lib/conditionalCacheFilter.class.php

[php]
class conditionalCacheFilter extends sfFilter
{
  public function execute($filterChain)
  {
    $context = $this->getContext();
    if (!$context->getUser()->isAuthenticated())
    {
      foreach ($this->getParameter('pages') as $page)
      {
        $context->getViewCacheManager()->addCache($page['module'], $page['action'], array('lifeTime' => 86400));
      }
    }

    // Nächsten Filter ausführen
    $filterChain->execute();
  }
}

Sie müssen diesen Filter in der Datei filters.yml vor dem sfCacheFilter registrieren, wie in Listing 12-7 zu sehen.

Listing 12-7 - Registrierung Ihres eigenen Filters, in frontend/config/filters.yml

...
security: ~

conditionalCache:
  class: conditionalCacheFilter
  param:
    pages:
      - { module: article, action: show }

cache: ~
...

Leeren Sie den Cache (damit die neue Filterklasse geladen wird), und der bedingte Cache ist einsatzbereit. Es schaltet den Cache für die Seiten an, die Sie im Parameter pages angegeben haben, sofern der Benutzer nicht authentifiziert ist.

Die Methode addCache() der Klasse sfViewCacheManager erwartet die Namen eines Moduls und einer Action sowie ein assoziatives Array mit den gleichen Parametern, die sie auch in der cache.yml angeben würden. Wenn Sie z.B. festlegen wollen, dass die Action article/show mit Layout und einer Lebensdauer von 3600 Sekunden gecachet werden soll, schreiben Sie folgendes:

[php]
$context->getViewCacheManager()->addCache('article', 'show', array(
  'withLayout' => true,
  'lifeTime'   => 3600,
));

SIDEBAR Alterantive Speicherorte für den Cache

Standardmäßig speichert das Cachesystem von Symfony seine Informationen in Dateien auf der Festplatte des Webservers. Möglicherweise wollen Sie die Daten aber auch im Hauptspeicher ablegen (z.B. mittels memcached), oder in einer Datenbank (vor allem, wenn Sie von mehreren Servern auf den Cache zugreifen oder die Entfernung von Daten beschleunigen wollen). Symfonys Standard-Cachesystem können Sie einfach ändern, da die Klasse, die der View-Cache-Manager von Symfony verwendet, in factories.yml festgelegt ist.

Standard-Factory für die Speicherklasse des View-Caches ist sfFileCache:

view_cache:
    class: sfFileCache
    param:
      automaticCleaningFactor: 0
      cacheDir:                %SF_TEMPLATE_CACHE_DIR%

Sie können in der Angabe class Ihre eigene Speicherklasse angeben oder eine der von Symfony bereitgestellten Alternativen (z.B. sfAPCCache, sfEAcceleratorCache, sfMemcacheCache, sfSQLiteCache oder sfXCacheCache). Die Parameter unterhalb des Schlüssels param werden dem Konstruktor Ihrer Klasse als assioziatives Array übergeben. Jede solche Speicherklasse muss alle Methoden abstrakten Methoden aus sfCache implementieren. In Kapitel 19 erfahren Sie mehr über dieses Thema.

Verwendung des superschnellen Caches

Selbst eine gecachete Seite bedingt die Ausführung von PHP-Code. Symfony muss die Konfiguration laden, die Antwort zusammenstellen usw. Wenn Sie wirklich sicher sind, dass eine Seite sich für eine Weile nicht ändern wird, können Sie Symfony komplett umgehen, indem Sie den resultierenden HTML-Code direkt in den Ordner web/ schreiben. Dies funktioniert durch mod_rewrite im Apache, vorausgesetzt, in Ihren Routingregeln ist ein Muster angegeben, das ohne Suffix ist bzw. auf .html endet.

Sie können dies dann manuell Seite für Seite mit einem einfachen Kommandozeilenaufruf durchführen:

> curl http://myapp.example.com/user/list.html > web/user/list.html

Danach findet Apache jedes Mal, wenn die Action user/list angefragt wird, die passende Seite list.html und umgeht Symfony komplett. Dies erkaufen Sie sich allerdings damit, dass Sie den Seitencache nicht mehr mit Symfony kontrollieren können (Lebensdauer, automatische Löschung usw.) - aber der Geschwindigkeitsgewinn ist beeindruckend.

Alternativ dazu können Sie auch das Symfony-Plugin sfSuperCache verwenden, dass diesen Prozess automatisiert und die Angabe einer Lebensdauer sowie das Löschen dieses Caches unterstützt. In Kapitel 17 erfahren Sie mehr über Plugins.

SIDEBAR Andere Beschleunigungshilfen

Zusätzlich zum HTML-Cache besitzt Symfony noch zwei andere Cachemechanismen, die komplett automatisiert und für den Entwickler völlig transparent sind. In der Produktivumgebung werden die Konfiguration und die Template-Übersetzungen ohne weiteres Zutun in Dateien unterhalb der Verzeichnisse myproject/cache/config/ und myproject/cache/i18n/ gespeichert.

PHP-Beschleuniger (engl. accelerators, auch Bytecode-Caches genannt), wie eAccelerator, APC oder XCache, erhöhen ebenfalls die Geschwindigkeit von PHP, indem sie den Quellcode im übersetzten Zustande speichern, so dass der Overhead des Code-Parsens und Übersetzens fast komplett entfällt. Die Beschleuniger sind mit Symfony kompatibel und können die Geschwindigkeit einer Anwendung locker verdreifachen. In Produktivumgebung für Symfony-Anwendungen mit großer Reichweite sind sie auf jeden Fall zu empfehlen.

Mit einem PHP-Beschleuniger können Sie mit der Klasse sfProcessCache persistent Daten im Speicher halten, damit nicht für jeden Request die gleichen Berechnungen durchgeführt werden müssen. Und wenn Sie das Ergebnis einer rechenintensiven Funktion cachen wollen, könnten Sie wahrscheinlich das Objekt sfFunctionCache benötigen. In Kapitel 18 erfahren Sie mehr über diese Mechanismen.

Elemente aus dem Cache entfernen

Wenn sich Scripte oder Daten Ihrer Anwendung ändern, enthält der Cache veraltete Informationen. Um Inkoherenz und Fehler zu vermeiden, können Sie Teile des Caches auf viele verschiedene Arten löschen, ganz nach Ihren Bedürfnissen.

Löschen des gesamten Caches

Der Task cache:clear des symfony-Kommandozeilentools löscht den Cache (HTML, Konfiguration und I18n-Cache). Sie können ihm Argumente übergeben, um nur einen Teil des Caches zu löschen, wie in Listing 12-8 gezeigt. Denken Sie daran, es nur aus dem Wurzelverzeichnis des symfony-Projekts aufzurufen.

Listing 12-8 - Löschen des Caches

// Löscht den ganzen Cache
> php symfony cache:clear

// Kurzschreibweise
> php symfony cc

// Löscht nur den Cache der Anwendung frontend
> php symfony cache:clear frontend

// Löscht nur den HTML-Cache der Anwendung frontend
> php symfony cache:clear frontend template

// Löscht nur den Konfigurationscache der Anwendung frontend
> php symfony cache:clear frontend config

Löschen von bestimmten Teilen des Caches

Sobald die Datenbank aktualisiert wird, muss für die Actions, die auf den veränderten Daten basieren, der Cache gelöscht werden. Sie könnten natürlich den ganzen Cache leeren, was allerdings auch alle anderen gecacheten Actions verwerfen würde, die nichts mit der Modeländerung zu tun haben. An dieser Stelle kommt die Methode remove() von sfViewCacheManager ins Spiel. Sie erwartet als Argument eine interne URI (die gleiche Art, die Sie auch einem link_to() übergeben würden), und leert den damit verbundenen Actioncache.

Stellen Sie sich beispielsweise vor, die Action update des Moduls user verändert die Felder des Objekts User. Die gecacheten Versionen der Actions list und show müssen nun gelöscht werden, ansonsten würden alte Versionen mit fehlerhaften Daten angezeugt. Hierfür benutzen Sie die Methode remove(), wie in Listing 12-9 zu sehen.

Listing 12-9 - Löschen des Caches für eine bestimmte Action, in modules/user/actions/actions.class.php

[php]
public function executeUpdate()
{
  // Den User aktualisieren
  $user_id = $this->getRequestParameter('id');
  $user = UserPeer::retrieveByPk($user_id);
  $this->foward404Unless($user);
  $user->setName($this->getRequestParameter('name'));
  ...
  $user->save();

  // Den Cache für Actions löschen, die mit dem User zusammenhängen
  $cacheManager = $this->getContext()->getViewCacheManager();
  $cacheManager->remove('user/list');
  $cacheManager->remove('user/show?id='.$user_id);
  ...
}

Partials, Komponenten und Komponentenslots aus dem Cache zu löschen ist etwas schwieriger. Da Sie ihnen jede Art von Parametern übergeben können (auch Objekte), ist es fast unmöglich, hinterher die gecachete Version zu ermitteln. Richten wir unseren Blick auf die Partials, denn die anderen Templatekomponenten verhalten sich analog. Symfony identifiziert ein gecachetes Partial über einen speziellen Prefix (sf_cache_partial), den Namen des Moduls, den Namen des Partials und ein Hash aus allen Parametern des Aufrufs, wie folgt:

[php]
// Ein Partial, das so aufgerufen wird:
<?php include_partial('user/mein_partial', array('user' => $user) ?>

// wird im Cache so identifiziert:
@sf_cache_partial?module=user&action=_mein_partial&sf_cache_key=bf41dd9c84d59f3574a5da244626dcc8

In der Theorie können Sie ein gecachetes Partial mit der Methode remove() entfernen, wenn Sie die Werte des Parameterhashs kennen, der es identifiziert; dies jedoch ist nicht praktikabel. Wenn Sie jedoch beim Aufruf von include_partial() einen Parameter namens sf_cache_key übergeben, können Sie das Partial im Cache über einen Ihnen bekannten Wert identifizieren. Wie Sie in Listing 12-10 sehen können, wird das Entfernen eines einzelnen gecacheten Partials - z.B. um ein Partial eines aktualisierten Objekts User aus dem Cache zu löschen - ganz einfach.

Listing 12-10 - Löschen von Partials aus dem Cache

[php]
<?php include_partial('user/mein_partial', array(
  'user'         => $user,
  'sf_cache_key' => $user->getId()
) ?>

// wird im Cache so identifiziert:
@sf_cache_partial?module=user&action=_mein_partial&sf_cache_key=12

// _mein_partial für einen bestimmten User aus dem Cache löschen mit
$cacheManager->remove('@sf_cache_partial?module=user&action=_mein_partial&sf_cache_key='.$user->getId());

Um Templatefragmente zu löschen, können Sie die gleiche Methode remove() verwenden. Der Schlüssel, der das Fragment im Cache identifiziert, ist genauso wie oben aus dem Prefix sf_cache_partial, dem Modulnamen, dem Namen der Action und dem sf_cache_key (also dem eindeutigen Namen des Cachefragments, der dem Helper cache() übergeben wird). Listing 12-11 zeigt ein Beispiel.

Listing 12-11 - Löschen von Templatefragmenten aus dem Cache

[php]
<!-- Gecacheter Code -->
<?php if (!cache('users')): ?>
  ... // Irgendwas
  <?php cache_save() ?>
<?php endif; ?>

// wird im Cache so identifiziert
@sf_cache_partial?module=user&action=list&sf_cache_key=users

// Löschen mit
$cacheManager->remove('@sf_cache_partial?module=user&action=list&sf_cache_key=users');

SIDEBAR Selektives Löschen des Caches kann Ihr Gehirn beschädigen

Der schwierigste Teil beim Löschen des Caches ist, festzustellen, welche Actions von einer Datenaktualisierung beeinflusst sind.

Stellen Sie sich z.B. vor, eine Anwendung hat ein Modul namens publication, das Publikationen auflistet (Action list) und näher beschreibt (Action show), zusammen mit Details über die entsprechenden Autoren (Instanzen der Klasse User). Wenn Sie nun einen Datensatz in User ändern, wird das alle Beschreibungen der Publikationen dieses Users verändern, und die gesamte Liste der Publikationen. Dies bedeutet, dass die Action update im Modul user in etwa so aussehen sollte:

[php]
$c = new Criteria();
$c->add(PublicationPeer::AUTHOR_ID, $this->getRequestParameter('id'));
$publications = PublicationPeer::doSelect($c);

$cacheManager = sfContext::getInstance()->getViewCacheManager();
foreach ($publications as $publication)
{
  $cacheManager->remove('publication/show?id='.$publication->getId());
}
$cacheManager->remove('publication/list');

Wenn Sie den HTML-Cache verwenden, müssen Sie einen guten Überblick über die Abhängigkeiten zwischen Model und Actions behalten, um nicht durch falsch verstandene Beziehungen neue Fehler einzubringen. Behalten Sie im Hinterkopf, dass alle Aktionen, die das Model verändern, wahrscheinlich eine Reihe von remove()-Aufrufen beinhalten müssten, wenn der HTML-Cache irgendwo in der Anwendung verwendet wird.

Und wenn Sie Ihr Gehirn nicht mit allzu tiefgehender Analyse zermartern wollen, können Sie einfach jedes Mal den gesamten Cache leeren, wenn Sie Daten in der Datenbank aktualisiert haben . . .

Mehrere Teile des Caches auf einmal löschen (Neu in Symfony 1.1)

Die Methode remove() nimmt Schlüssel mit Platzhaltern entgegen. Dies ermöglicht es Ihnen, mehrere Teile des Caches mit einem einzigen Aufruf zu löschen. Sie können z.B. folgendes tun:

[php]
$cacheManager->remove('user/show?id=*');    // Entfernt die Datensätze aller Benutzer

Ein weiteres gutes Beispiel ist eine Anwendung, die mehrere verschiedene Sprachen anzeigt, wobei das Sprachkürzel in den URLs auftaucht. Die URL einer Seite mit einem Benutzerprofil sollte in etwa so aussehen:

http://www.myapp.com/en/user/show/id/12

Um das gecachete Profil eines Users mit der id 12 in allen Sprachen zu löschen, können Sie einfach folgendes aufrufen:

[php]
$cache->remove('user/show?sf_culture=*&id=12');

Dies funktioniert auch bei Partials:

[php]
$cacheManager->remove('@sf_cache_partial?module=user&action=_my_partial&sf_cache_key=*');    // Löscht den Cache für alle Schlüssel

Die Methode remove() nimmt noch zwei weitere Parameter entgegen, die Ihnen erlaubt, für welche Hosts und Vary-Header der Cache zu löschen ist. Dies kann notwendig sein, da Symfony für jeden Host und jeden Vary-Header einen eigenen Cache vorhält, so dass zwei Anwendungen, die auf der gleichen Codebasis arbeiten, aber über unterschiedliche Hostnamen aufgerufen werden, auch verschiedene Caches verwenden. Dies kann z.B. dann von großem Nutzen sein, wenn eine Anwendung auch die Subdomain als Abfrageparameter verarbeitet (wie http://php.askeet.com und http://life.askeet.com). Wenn Sie die beiden letzten Parameter nicht angeben, löscht Symfony den Cache für den aktuellen Host und für den Vary-Header all. Wenn Sie den Cache für einen anderen Host löschen wollen, rufen Sie remove() wie folgt auf:

[php]
$cacheManager->remove('user/show?id=*');                     // Entfernt die Datensätze aller User für den aktuellen Host
$cacheManager->remove('user/show?id=*', 'life.askeet.com');  // Entfernt die Datensätze aller User für den HostRemove life.askeet.com
$cacheManager->remove('user/show?id=*', '*');                // Entfernt die Datensätze aller User für alle Hosts

Die Methode remove() funktioniert bei allen Caching-Strategien, die Sie in factories.yml angeben können (nicht nur bei sfFileCache, sondern auch bei sfAPCCache, sfEAcceleratorCache, sfMemcacheCache, sfSQLiteCache und sfXCacheCache).

Löschen des Caches über Anwendungsgrenzen hinweg (Neu in symfony 1.1)

Das Löschen des Caches über die Grenzen der Anwendungen hinweg kann ein Problem darstellen. Wenn beispielsweise der Administrator einen Datensatz der Tabelle user in der backend-Anwendung ändert, müssen alle Actions in der frontend-Anwendung, die von diesem User abhängen, aus dem Cache gelöscht werden. Allerdings kennt der View-Cache-Manager der backend-Anwendung die Routingregeln der frontend-Anwendung nicht (die Anwendungen sind voneinander völlig isoliert. Folglich können Sie im Backend nicht einfach folgendes schreiben:

[php]
$cacheManager = sfContext::getInstance()->getViewCacheManager(); // Viewmanager für das Backend ermitteln
$cacheManager->remove('user/show?id=12');                        // Dieses Muster wird nicht gefunden, da das Template im Frontend gecachet ist

Die Lösung ist, das sfCache-Objekt von Hand mit den Einstellungen des Frontend-Cachemanagers zu initialisieren. Praktischerweise stellen alle Cache-Klassen in Symfony eine Methode namens removePattern() zur Verfügung, die das gleiche match wie remove() im View-Cache-Manager.

Wenn also die backend-Anwendung den Cache der Action user/show im Frontend für den User mit der id 12 löschen muss, können Sie folgendes schreiben:

[php]
$frontend_cache_dir = sfConfig::get('sf_root_cache_dir') . DIRECTORY_SEPARATOR . 'frontend' . DIRECTORY_SEPARATOR . SF_ENV . DIRECTORY_SEPARATOR . 'template';
$cache = new sfFileCache(array('cache_dir' => $frontend_cache_dir)); // Verwende die Einstellungen, die in der factories.yml des Frontends definiert sind
$cache->removePattern('user/show?id=12');

Für andere Caching-Strategien müssen Sie nur die Initialisierung des Cache-Objekts ändern, aber der Löschprozess bleibt der gleiche:

[php]
$cache = new sfMemcacheCache(array('prefix' => 'frontend'));
$cache->removePattern('user/show?id=12');

Den Cache testen und überwachen

Wenn mit dem HTML-Caching nicht richtig umgegangen wird, kann das zu Inkoherenzen der angezeigten Daten führen. Wenn Sie den Cache für ein Element deaktivieren, sollten Sie es gründlich testen und die Ausführung überwachen, um es zu tunen. <!-- Unklare Formulierung: Each time you disable the cache for an element, you should test it thoroughly and monitor the execution boost to tweak it. -->

Erstellen einer Staging-Umgebung

Das Cachingsystem ist anfällig gegenüber neuen Fehlern in der Produktionsumgebung, die in der Entwicklungsumgebung nicht erkannt werden können, da dort das HTML-Caching standardmäßig nicht aktiviert ist. Wenn Sie den HTML-Cache für einige Actions aktivieren wollen, sollten Sie eine neue Umgebung erstellen, die wir hier als "staging" (Bühne) bezeichnen. Sie sollte die gleichen Einstellungen wie die Umgebung prod (also mit aktiviertem Cache) haben, aber mit web_debug auf on.

Zur Einrichtung bearbeiten Sie die Datei settings.yml Ihrer Anwendung und fügen am Beginn die Zeilen aus Listing 12-12 ein.

Listing 12-12 - Einstellungen für die Umgebung staging, in frontend/config/settings.yml

staging:
  .settings:
    web_debug:  on
    cache:      on

Zusätzlich erzeugen Sie einen neuen Frontcontroller, indem Sie den Produktions-Controller (wahrscheinlich myproject/web/index.php) in eine neue Datei namens frontend_staging.php kopieren. Bearbeiten Sie und ändern Sie die Werte SF_ENVIRONMENT und SF_DEBUG wie folgt:

[php]
define('SF_ENVIRONMENT', 'staging');
define('SF_DEBUG',        true);

Das war es schon - Sie haben eine neue Umgebung erstellt. Um sie zu verwenden, geben Sie den Namen des Frontcontrollers nach dem Domainnamen an:

http://myapp.example.com/frontend_staging.php/user/list

Überwachen der Performance

In Kapitel 16 werden wir die Web-Debug-Toolbar und ihre Inhalte kennenlernen. Da diese Toolbar jedoch wichtige Informationen über gecachete Elemente bereitstellt, folgt hier eine kurze Beschreibung ihrer Eigenschaften bezüglich des Cachings.

Wenn Sie eine Seite mit cachebaren Elementen (Actions, Partials, Fragmente usw.) ansurfen, zeigt die Web-Debug-Toolbar (in der oberen rechten Ecke des Fensters) einen Button, mit dem Sie den Cache unterdrücken können. Es hat die Form eines grünen, geschwungenen Pfeils, wie in Abbildung 12-4 zu sehen. Dieser Button lädt die Seite neu und erzwingt dabei die Abarbeitung der gecachten Elemente. Beachten Sie jedoch, dass der Cache dabei nicht geleert wird.

Die letzte Zahl auf der rechten Seite der Toolbar zeigt die Laufzeit der Ausführung des Requests. Wenn Sie den Cache auf einer Seite aktivieren, sollte diese Zahl kleiner werden, wenn Sie die Seite zum zweiten Mal laden, da Symfony dann die Daten aus dem Cache verwendet, anstatt die Scripte erneut auszuführen. Mit dieser Anzeige können Sie relativ einfach die Verbesserungen durch das Caching überprüfen.

Figure 12-4 - Web-Debug-Toolbar bei Seiten, die Caching verwenden

Web-Debug-Toolbar bei Seiten, die Caching verwenden

Die Debugtoolbar zeigt außerdem die Anzahl der Datenbankabfragen, die während der Bearbeitung des Requests ausgeführt werden, und Details ihrer Laufzeiten nach Kategorie (klicken Sie auf die Gesamtlaufzeit, um diese Details zu zeigen). Die Überwachung dieser Daten in Verbindung mit der Gesamtlaufzeit wird Ihnen dabei helfen, die Performanceverbesserungen des Caches genau zu messen.

Benchmarken

Der Debugmodus verringert die Ausführungsgeschwindigkeit Ihrer Anwendung erheblich, da eine Menge Information protokolliert und durch die Web-Debug-Toolbar verfügbar gemacht werden. Aus diesem Grund ist die Laufzeit, die angezeigt wird, wenn Sie in Ihrer staging-Umgebung surfen, nicht repräsentativ für die Produktivumgebung, in welcher der Debugmodus abgeschaltet ist.

Um einen besseren Einblick über die Laufzeiten jedes Requests zu erhalten, sollten Sie Benchmark-Tools wie Apache Bench oder JMeter verwenden. Diese Tools ermöglichen Ihnen, Ladetests durchzuführen, und geben zwei wichtige Informationen zurück: die durchschnittliche Ladezeit einer bestimmten Seite und die maximale Kapazität Ihres Servers. Die durchschnittliche Ladezeit ist sehr nützlich, wenn Sie die Performanceverbesserungen nach der Cacheaktivierung überwachen wollen.

Identifizieren gecachter Teile

Wenn die Web-Debug-Toolbar aktiviert ist, werden die gecacheten Elemente auf einer Seite durch einen roten Rahmen gekennzeichnet, der jeweils oben links eine Box mit Informationen zum Cache besitzt, wie in Abbildung 12-5 gezeigt. Der Hintergrund der Box ist blau, wenn das Element ausgeführt wurde, und gelb, wenn es aus dem Cache stammt. Wenn Sie auf den Informationslink klicken, werden der Bezeichner des Cache-Elements, die Lebensdauer und die verstrichene Zeit seit seiner letzten Aktualisierung angezeigt. Dies wird Ihnen helfen, Probleme im Zusammenhang mit kontextfremden Elementen zu identifizieren, zu sehen, wann das Element erzeugt wurde, und welche Teile eines Templates Sie letztlich cachen können.

Figure 12-5 - Kennzeichnung von gecacheten Elementen auf einer Seite

Kennzeichnung von gecacheten Elementen auf einer Seite

HTTP 1.1 und clientseitiges Caching

Das HTTP 1.1-Protokoll definiert eine Reihe von Headern, die von großem Nutzen sein können, um eine Anwendung noch schneller zu machen, indem sie das Cacheverhalten des Browsers beeinflussen.

Die HTTP 1.1-Spezifikation, die das World Wide Web Consortium (W3C, http://www. w3.org/Protocols/rfc2616/rfc2616-sec14.html) veröffentlicht, beschreibt diese Header im Detail. Wenn für eine Action das Caching aktiviert ist und dabei die Option with_layout verwendet wird, kann Sie eine oder mehrere der Mechanismen verwenden, die in den folgenden Abschnitten vorgestellt werden.

Selbst wenn einige Browser Ihrer Seitennutzer HTTP 1.1 nicht unterstüzten, ist es kein Risiko, die Cachemöglichkeiten von HTTP 1.1 zu nutzen. Wenn ein Browser Header erhält, die er nicht versteht, ignoriert er sie einfach, und deshalb empfehlen wir Ihnen, die Cachemechanismen von HTTP 1.1 zu verwenden.

Zusätzlich werden die HTTP 1.1-Header auch von Proxys und Cachingservern interpretiert. Selbst wenn also der Browser des Benutzers kein HTTP 1.1 versteht, kann immer noch ein Proxy auf dem Weg daraus Vorteile ziehen.

Verwendung des ETag-Headers, damit unveränderter Inhalt nicht übertragen werden müssen

Wenn ETag aktiviert ist, fügt der Webserver einen speziellen Header in die Antwort ein, die eine Signatur der Antwort selbst darstellt.

ETag: "1A2Z3E4R5T6Y7U"

Der Browser speichert diese Signatur und sendet sie beim nächsten Request auf die gleiche Seite mit. Wenn die neue Signatur zeigt, dass die Seite sich seit dem vorherigen Request nicht verändert hat, sendet der Server keine Antwort zurück. Stattdessen schickt er nur einen Header 304: Not modified (dt.: "Nicht verändert"). Dies spart CPU-Zeit (z.B. wenn Ausgabekompression mit gzip aktiviert ist) und Bandbreite (Seitentransfer) auf der Serverseite, sowie Zeit (für den Seitentransfer) auf der Seite des Clients. Im Großen und Ganzen werden Seiten mit ETag aus dem Cache noch schneller geladen als solche ohne.

In Symfony aktivieren Sie die Verwendung von ETag für die ganze Anwendung in settings.yml. Dies ist die standardmäßige ETag-Einstellung:

all:
  .settings:
    etag: on

Für Actions, die mit Layout gecachet sind, wird die Antwort direkt aus dem cache/-Verzeichnis geholt, so dass dieser Prozess noch schneller ist.

Verwendung des Last-Modified-Headers, damit immer noch gültiger Inhalt nicht übertragen werden muss

Wenn der Server eine Antwort zum Browser schickt, kann er einen speziellen Header übergeben, der angibt, wann die Daten auf der Seite zuletzt geändert wurden:

Last-Modified: Sat, 23 Nov 2006 13:27:31 GMT

Browser können diesen Header verarbeiten und bei erneutem Aufruf der Seite einen passenden If-Modified-Header (dt.: "Wenn-Verändert") setzen:

If-Modified-Since: Sat, 23 Nov 2006 13:27:31 GMT

Der Server kann dann den Wert vom Client mit dem von der Anwendung vergleichen. Wenn sie übereinstimmen, gibt der Server einfach ein 304: Not modified-Header (dt.: "Nicht verändert") zurück, was Bandbreite und Rechenzeit spart, wie bei den ETags.

In Symfony können sie den Antwortheader Last-Modified wie jeden anderen Header setzen. Sie könnten ihn beispielsweise so in einer Action verwenden:

[php]
$this->getResponse()->setHttpHeader('Last-Modified', $this->getResponse()->getDate($timestamp));

Dieses Datum könnte das tatsächliche Datum der letzten Aktualisierung der Daten sein, die auf der Seite verwendet werden, welches aus der Datenbank oder aus dem Dateisystem abgeleitet wird. Die Methode getDate() des sfResponse-Objekts konvertiert einen Zeitstempel in einen formatierten Datumswert, wie ihn der Last-Modified-Header nach RFC1123 benötigt.

Verwendung des Vary-Headers, um verschiedene gecachte Versionen einer Seite zu ermöglichen

Ein weiterer HTTP-1.1-Header ist Vary. Er legt fest, von welchen Faktoren eine Seite abhängt, und wird von Browsern oder Proxys verwendet, um Cache-Schlüssel zu erstellen. Wenn beispielsweise der Seiteninhalt von Cookies abhängt, können Sie den Vary-Header wie folgt setzen:

Vary: Cookie

Meistens ist es sehr schwierigt, Caching für Actions zu aktivieren, weil die Seite sich je nach Cookie, Benutzersprache oder irgendetwas anderem verändert. Wenn Ihnen die Größe Ihres Caches egal ist, setzen Sie den Vary-Header der Antwort entsprechend. Dies kann für die gesamte Anwendung geschehen oder für jede Action, indem Sie die cache.yml-Konfigurationsdatei oder die entsprechenden Methoden des sfResponse-Objekts wie folgt verwenden:

[php]
$this->getResponse()->addVaryHttpHeader('Cookie');
$this->getResponse()->addVaryHttpHeader('User-Agent');
$this->getResponse()->addVaryHttpHeader('Accept-Language');

Symfony wird im Cache dann verschiedene Versionen der Seite für jeden Wert dieser Parameter vorhalten. Dies wird die Größe des Caches erhöhen, aber wann immer der Server einen Request empfängt, der zu den Headern passt, wird die Antwort aus dem Cache genommen, anstatt eine Verarbeitung anzustoßen. Dies wird die Performance von Seiten, die sich nur durch Request-Header verändern, enorm steigern.

Verwendung des Cache-Control-Headers, um clientseitiges Cachen zu ermöglichen

Obwohl bereits einige Header hinzugefügt wurden, wird der Browser bislang jedes Mal eine Anfrage zum Server senden, selbst wenn er eine Version der Seite im Cache hält. Dies können Sie vermeiden, indem Sie in der Antwort die Header Cache-Control und Expires hinzufügen. Diese Header sind sind in PHP normalerweise abgeschaltet, aber Symfony kann dieses Verhalten jedoch übersteuern, um überflüssige Requests auf Ihren Server zu vermeiden.

Wie üblich lösen Sie dieses Verhalten aus, indem Sie eine Methode des sfResponse-Objekts aufrufen. In einer Action definieren Sie die maximale Zeit (in Sekunden), die eine Seite gecachet werden darf.

[php]
$this->getResponse()->addCacheControlHttpHeader('max_age=60');

Sie können auch angeben, unter welchen Bedingungen eine Seite gecachet werden darf, so dass beispielsweise der Cache des Providers keine Kopie privater Daten (z.B. Kontonummern) aufbewahrt:

[php]
$this->getResponse()->addCacheControlHttpHeader('private=True');

Mit den Cache-Control-Direktiven erhalten Sie die Möglichkeit, die diversen Caching-Mechanismen zwischen Ihrem Server und dem Browser des Benutzers genau zu regeln. Eine detaillierte Auflistung dieser Direktiven entnehmen Sie den Cache-Control-Spezifikationen des W3C.

Der letzte Header, der mit Symfony gesetzt werden kann, ist Expires:

[php]
$this->getResponse()->setHttpHeader('Expires', $this->getResponse()->getDate($timestamp));

ACHTUNG Wenn Sie den Cache-Control-Mechanismus aktivieren, ist eine der wichtigsten Konsequenzen, dass die Logdateien Ihrer Webserver nicht mehr alle Requests der Benutzer anzeigen, sondern nur noch diejenigen, die wirklich am Server ankommen. Wenn die Performance besser wird, könnte also die anhand der Statistiken gemessene Popularität der Seite sinken.

Zusammenfassung

Das Cachesystem ermöglicht unterschiedliche Performancegewinne, je nach dem, welche Art von Cache Sie gewählt haben. Die verschiedenen Cachetypen, geordnet nach dem höchsten bis zum niedrigsten Geschwindigkeitsgewinn, sind:

  • Super-Cache
  • Action-Cache mit Layout
  • Action-Cache ohne Layout
  • Fragment-Cache im Template

Zusätzlich können auch Partials und Komponenten gecachet werden.

Wenn Sie eine Datenänderung im Model oder in der Session dazu zwingt, den Cache im Hinblick auf die Koherenz zu leeren, können Sie dies für die größmögliche Performance fein granulieren - Sie löschen einfach nur die Elemente, die sich geändert haben, und behalten die anderen.

Denken Sie jedoch daran, alle Seiten mit aktiviertem Cache mit höchster Sorgfalt zu testen, da sich möglicherweise neue Fehler zeigen, wenn Sie die falschen Elemente cachen oder vergessen, den Cache zu löschen, wenn sich die zugrunde liegenden Daten ändern. Eine eigene "Staging"-Umgebung, die auf das Testen des Caches abzielt, ist für diesen Zweck von großem Nutzen.

Schließlich sollten Sie noch das bestmögliche aus dem HTTP-1.1-Protokoll herausholen, indem Sie Symfonys erweitertes Cache-Tuning verwenden, das den Client mit in den Cachevorgang einbindet und so nochmals Geschwindigkeitsvorteile erzielt.