Caching Framework: automatisch Cache leeren bei Datensatzänderung

Das Caching Framework lässt sich gut verwenden, um aufwändig generierte/abgefragte Daten zur Wiederverwendung schneller parat zu haben. Die prinzipielle Funktionsweise haben wir in „Caching Framework nutzen“ erklärt und findet sich auch in der Doku sowie in zahlreichen anderen Blogs.
Was aber oftmals fehlt: wie aktualisiert man den Cache bzw. invalidert ihn bei Veränderung der Daten?

Häufig hängt der Inhalt des Caches von Datensätzen ab. D.h. der Cache-Inhalt veraltet, wenn sich ein Datensatz verändert. Und damit ist auch der Ansatzpunkt für die Invalidierung klar: der processDatamap_afterDatabaseOperations-Hook im DataHandler. Er wird immer nach Datenbankoperationen („new“ bzw. „update“) aufgerufen und bekommt auch den Taballennamen mit übergeben. Somit ist es recht einfach, die eigenen Datensätze zu erkennen und auf die Veränderung zu reagieren:

EXT:my_extension/Classes/Hooks/DataHandler.php:

<?php
namespace Netzhaut\MyExtension\Hooks;

use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class DataHandler
{
    public function processDatamap_afterDatabaseOperations($status, $tableName, $recordId, array $databaseData, \TYPO3\CMS\Core\DataHandling\DataHandler $dataHandler)
    {
        if ($tableName === 'tx_myextension_domain_model_example') {
            $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('myCache');
            $cache->flushByTag('tag_123');
        }
    }
}

Dann noch am Hook registrieren, und fertig:

EXT:my_extension/ext_localconf.php

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['myextension_clearcfcache'] = 'Netzhaut\\MyExtension\\Hooks\\DataHandler';

Links

Caching kurzlebiger Inhalte (z.B. News)

Ein typischer Fall, in dem Kunden und Entwickler das Caching von TYPO3 bisher verfluchten, war die Nutzung eines Plugins wie tt_news, bei dem sich die anzuzeigenden Datensätze zwar geändert hatten, die Aktualisierung des Caches aber erst nach Ablauf dessen Gültigkeitszeitraums  erfolgte. (Die Möglichkeit, generell den Cache zu deaktivieren, ist böse und wir daher nicht näher betrachtet). Über die Einstellung TCEMAIN.clearCacheCmd auf der Seite, die die Datensätze enthält, ließ sich zwar der Cache einzelner (oder aller) Seiten bei Änderungen invalidieren, jedoch ist dies nicht wirklich sinnvoll und praktikabel:

  • Man muss entweder die Liste der Seiten-IDs pflegen oder mittels „all“ den Cache aller Seiten lsöchen, unahängig davon, ob das Plugin dort überhaupt eingesetzt ist.
  • Man löscht stets den Cache der gesamten Seite, obwohl sich ja nur ein Inhaltselement aktualisieren soll.

Ende Februar hatte Fabrizio in seinem Blog eine Idee vorgestellt, wie auf Contentelement-Ebene ein individuelleres Caching ermöglicht werden könnte. Diese stieß auf viel Interesse und schaffte es schnell in den TYPO3-Core (4.7), auch ein Backport in 4.5 und 4.6 ist vorgesehen.

Weiterlesen»

Caching Framework nutzen

Für umfangreichere Datenkonstrukte, die häufig verwendet werden oder aber aufwändig zu erzeugen sind, ist ein Cache nützlich. Ein typischer Fall sind Dateilisten, die sich auf Verzeichnissen generieren (z.B. für eine einfache Bildergalerie). Die Inhalte der Verzeichnisse ändern sich meist nur extrem selten – wozu also immer wieder aufs Neue via Dateisystem auslesen, welche Dateien existieren? Hier ist es doch naheliegender, die Liste zu cachen und nur selten oder gar nur via gezielter Anforderung zu aktalisieren.
Einen von vielen Fällen, wo das Caching Framework in einer eigenen Extension zum Einsatz kommen kann…

Weiterlesen»

Server mit memcached, php-memcache und aktiviertem TYPO3 (>4.3.0) Caching Framework

memcached ist perfekt zum cachen eigener Inhalte. Damit der Server damit ausgeruestet ist:

apt-get install memcached

Ist ein Server mit mehr als 2 Kernen ausgestattet, sollte das threaded Paket installiert.

Der memcached sollte den freien RAM vollstaendig ausnutzen (nicht ueberbuchen, damit’s nicht ins SWAP geht).
Die Speichermenge kann in

/etc/memcached.conf

eingestellt werden.

PHP kann eine API anbieten (die Applikationen muessen sich aber schon selbstaendig um die Verwendung und Organisation des Caches kuemmern: z.B. TYPO3 Extensions koennen vom TYPO3 Core Caching Framework via memcache profitieren )

Um die PHP Erweiterung zu installieren:

apt-get install php5-dev
pecl install memcache-3.0.6

Ideale PHP Werte in

/etc/php5/conf.d/memcache.ini

sind

[memcache]
memcache.dbpath="/var/lib/memcache"
memcache.maxreclevel=0
memcache.maxfiles=0
memcache.archivememlim=0
memcache.maxfilesize=0
memcache.maxratio=0
memcache.protocol=ascii

… ergaenzend fuer TYPO3, ausgelagert in

/etc/php5/conf.d/t3memcache.ini

ist folgendes von Vorteil

memcache.allow_failover=1
memcache.chunk_size=32768
memcache.default_port=11211
memcache.hash_function=fnv
memcache.hash_strategy=consistent
memcache.max_failover_attempts=20

Das „binary“ Protokoll wird von PHP nicht vollstaendig unterstuetzt, daher muss „ascii“ als sehr parser-intensives und langsameres Protokoll verwendet werden.

Damit TYPO3 vom memcache profitiert, folgende Einstellungen in der localconf.php vornehmen:

// ----- Caching with MemCache 4.3 only ----
$TYPO3_CONF_VARS['SYS']['caching']['cacheConfigurations'] = array (
    'cache_hash' => array(
	'frontend' => 't3lib_cache_frontend_VariableFrontend',
	'backend' => 't3lib_cache_backend_MemcachedBackend',
	'options' => array(
	    'servers' => array('tcp://localhost:11211'),
	)
    ),
    'cache_pages' => array(
	'frontend' => 't3lib_cache_frontend_VariableFrontend',
	'backend' => 't3lib_cache_backend_MemcachedBackend',
	'options' => array(
	    'servers' => array('tcp://localhost:11211'),
	)
    ),
    'cache_pagesection' => array(
	'frontend' => 't3lib_cache_frontend_VariableFrontend',
	'backend' => 't3lib_cache_backend_MemcachedBackend',
	'options' => array(
	    'servers' => array('tcp://localhost:11211'),
	)
    ),
);
$TYPO3_CONF_VARS['SYS']['useCachingFramework'] = '1';
// ----- /Caching with MemCache 4.3 only----

hier eine aktualisierte Version, die nicht das komplette cacheConfigurations Array ueberschreibt (danke fuer den Hinweis, Steffen).

 
// ----- Caching with MemCache - doesn't overwrite cacheConfigurations array completely -----
$TYPO3_CONF_VARS['SYS']['caching']['cacheConfigurations']['cache_hash'] = array(
	'frontend' => 't3lib_cache_frontend_VariableFrontend',
	'backend' => 't3lib_cache_backend_MemcachedBackend',
	'options' => array(
		'servers' => array('tcp://localhost:11211')
	)
);
$TYPO3_CONF_VARS['SYS']['caching']['cacheConfigurations']['cache_pages'] = array(
	'frontend' => 't3lib_cache_frontend_VariableFrontend',
	'backend' => 't3lib_cache_backend_MemcachedBackend',
	'options' => array(
		'servers' => array('tcp://localhost:11211')
	)
);
$TYPO3_CONF_VARS['SYS']['caching']['cacheConfigurations']['cache_pagesection'] = array(
	'frontend' => 't3lib_cache_frontend_VariableFrontend',
	'backend' => 't3lib_cache_backend_MemcachedBackend',
	'options' => array(
		'servers' => array('tcp://localhost:11211')
	)
);
$TYPO3_CONF_VARS['SYS']['useCachingFramework'] = '1';
// ----- /Caching with MemCache - doesn't overwrite cacheConfigurations array completely -----

Steht ein weiterer, dezidierter memcache Server bereit, sollte der in die ’servers‘ Arrays mit aufgenommen werden. Um split-brain in den Caches zu vermeiden und die Last besser zu koordinieren, ist es aber besser fuer jedes Segment einen eigenen, einzelnen Server zu verwenden (wenn man 3 Server uebrig hat…)