Caching Framework in Extensions

Extensions sollten um horizontal zu skalieren, Caches nicht in eigens gebauten $_SESSION Arrays oder Temporaeren SQL Tabellen halten, sondern das ab TYPO3 4.3.0 eingebaute und ab 4.3.1 vollstaendig umgesetzte Caching Framework (ein Backport aus der FLOW3 Entwicklung) verwenden.

Ein guter Artikel ist:

Bei der Entwicklung der Extensions ist natuerlich darauf zu achten, dass diese in der Form auch erst ab 4.3.1 korrekt arbeiten, und auf aelteren Installationen nicht funktionieren werden.

In kurzen Auszuegen:
In die ext_localconf.php folgendes hinzufuegen, wenn Memcached verwendet werden soll:

// If cache is not already defined, define it
if (!is_array($TYPO3_CONF_VARS['SYS']['caching']['cacheConfigurations']['my_extension'])) {
   $TYPO3_CONF_VARS['SYS']['caching'] ['cacheConfigurations']['my_extension'] = array(
      'backend' => 't3lib_cache_backend_MemcachedBackend', 'options' => array( 'servers' => array('localhost:11211'), ))
   );
}

In der Extension muss das cache Object erzeugt und initialisiert werden:

if (TYPO3_UseCachingFramework) {
   // Create the cache
   try {
      $GLOBALS['typo3CacheFactory']->create(
         'my_extension',
         't3lib_cache_frontend_VariableFrontend',
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['my_extension']['backend'],
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['my_extension']['options']
      );
   } catch(t3lib_cache_exception_DuplicateIdentifier $e) {
      // do nothing, the cache already exists
   }
   // Initialize the cache
   try {
      $this->cache = $GLOBALS['typo3CacheManager']->getCache(
         'my_extension'
      );
   } catch(t3lib_cache_exception_NoSuchCache $e) {
      // Unable to load
   }
}

Um jetzt mit dem Cache arbeiten zu koennen sind folgende Methoden vorhanden:

$this->cache->has($id);
$this->cache->get($id);
$this->cache->set($id, $content, $tags, $lifetime);

Um id, content, tags und lifetime muss man sich selber kuemmern…

Bei MemcacheBackend gilt zu beachten: Idealerweise keine $id laenger als 255 Byte und idealerweise keinen $content mit mehr als 1MByte … das TYPO3 Caching Framework bricht diese Grenzwerte zwar auf, allerdings ist die Performance dann so im Keller, dass man den Zwischenspeicher auch gleich auf Pergament schreiben kann.

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…)