#schongewusstPage SpeedTYPO3 Performance

TYPO3 Performance: So geht’s schneller!

TYPO3 Performance: So geht’s schneller!

TYPO3 und Performance sind Ziele, die erreichbar sind, aber in jedem Projekt unterschiedlich angegangen werden müssen. Es gibt im Netz genug Standardtipps für TYPO3-Projekte, z.B. “entfernt Extensions mit -$GLOBALS[‚TSFE‘]>noCache() = 1”. Das kennt man alles zur Genüge. Ich erzähle nun mal meine Erfahrungen anhand eines Projektes.

Messwerte

Man kann natürlich direkt Lasttests durchführen, aber für mich ist erst einmal das Gefühl entscheidend. Im ersten Schritt notiere ich mir simpel die Werte in einem Projektsetup und schaue mir an, was die Werte im AdminPanel ausgeben. Pro Seite hole ich mir um die 10 Zugriffszeiten, um einen guten Schnitt zu erhalten. Hinweis: Dies findet auf einem Stagingsystem statt, wo meine Zeiten nicht groß von außen beeinflusst werden.

Im zweiten Schritt ziehe ich Lasttests heran. Dazu würde ich auch jedem raten, der genug Zeit und Ressourcen hat.

Frontend Standards

Mit Tools wie GTMetrix  oder Google Page Speed wird ganz gut aufgezeigt, was im Frontend nicht rund läuft. Die Klassiker sind hier oft folgende Dinge:

  • Fehlerhaft eingestelltes Caching
  • Schlecht komprimierte Bilder
  • Kein GZIP aktiviert

Diese Dinge sollte man erst einmal beheben, wenn sie auftreten. Eine gute .htaccess reicht dort oft aus. Diese kompletten Punkte hat die Marit AG auf den TYPO3 Developer Days vorgestellt. Die Slides kann man sich hier ansehen: http://de.slideshare.net/MaritAG2009/marit-ag-page-speed-insight-100100-guide

Die Umstellung auf Grunt kann ich nur empfehlen. Es ist erst eine größere Hürde umzustellen, aber es hat später den Vorteil, dass sich die Komprimierung in TYPO3 ausschalten lässt. Hier gibt es den ersten Performancegewinn.

Menü

Mein größtes Problem ist seit Jahren das TYPO3 Menü. In vielen Projekten gibt es große Menüs mit x Levels. Pro Seitenaufruf wird hier auch entsprechend abgerufen, ob jemand eingeloggt ist, wie der Status der Seite ist, und natürlich muss auch der Link generiert werden. Bei einem der Projekte kam dann noch eine Bildgenerierung im Menü dazu. Dann stellte ich mir die Frage: Wie oft ändert sich so ein Menü?

Konsequenz: Ich speichere mir mein Menü in der Datenbank zwischen und lese es von dort als HTML aus. Aktive Menüzustände könnte man über Javascript setzen, wenn sie benötigt werden. Wem die Lösung mit Javascript nicht sauber genug ist, der kann natürlich auch pro Seite das Menü zwischenspeichern. Im Backend kann man per Hook auf das Verändern von Seiten reagieren und das Menü neu erzeugen lassen oder automatisch alle x Minuten per TYPO3 Task.

Diese Änderung hat uns bei diesem Projekt einen großen Performance-Sprung gebracht.

Code

Natürlich kann man mit einem Code auch genug Probleme haben. Pauschal kann ich mich hierzu nicht äußern, aber ein Refactoring nach einer gewissen Zeit ist immer sinnvoll, weil man oft einen anderen Blick auf die Dinge bekommt.

Ein Beispiel von mir: In einem Partial hatte ich an verschiedenen Stellen ein- und dieselbe Linkgenerierung. Hier konnte ich Performance gewinnen, indem ich z.B. den Link im Controller via uriBuilder erstellte. Das muss man von Fall zu Fall abwägen, aber bei x Produkten, bei denen drei Mal der Link generiert wurde, sparte ich gut 40 % der Zeit ein.

Datenbank

TYPO3 liefert sein Standardschema aus, und das ist auch soweit in Ordnung. Ich konnte so unsere Abfragen mit zwei Indizes beschleunigen: Zum einen wurden viele Sorting-Abfragen in Extensions mit einem passenden Index versorgt, zum anderen konnte ich bei der sys_file_reference etwas für unser Projekt verbessern:

CREATE TABLE sys_file_reference (
KEY sorting (tablenames,uid_foreign,fieldname,sorting_foreign),
);

Dieser Key sparte uns gut Zeit auf der Startseite.

Server

Dies ist nicht wirklich mein Gebiet, aber es kann nicht schaden, sich mal die Apache/nginx/PHP/MySQL-Einstellungen genauer anzusehen (zu lassen). Für mich brachte übrigens ein Umstieg von PHP 5.4 zu PHP 5.6 bei der TYPO3- Version 6.2 gut 10 % Gewinn ein.

Caching

Wir hatten vor längerer Zeit Helmut Hummel im Haus und diskutierten auch über das Caching, das TYPO3 unterstützt. Wir versuchten es dann erst mit Memcached und später mit Redis. Ich kann nur sagen: Wow! Dieser Sprung ist beachtlich.

Leider sind wir durch dieses Thema erstmal auch tief gefallen. Unsere Modelstruktur ist recht komplex und so ist der extbase_reflection_cache sehr groß. Dadurch bekam die Seite ziemliche Schwierigkeiten; so wurden Seiten teilweise nur noch in 7-8 Sekunden geladen. Unsere aktuelle Lösung sieht so aus und klappt für diesen Fall bestens:

if (class_exists('redis')) {

/** Database numbers 0 and 1 are used and flushed by the core unit tests and should not be used if possible. */

$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_pages']['backend'] = 'TYPO3\\CMS\\Core\\Cache\\Backend\\RedisBackend';

$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_pages']['options'] = array('defaultLifetime' => 3600, 'database' => 2);

$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_pagesection']['backend'] = 'TYPO3\\CMS\\Core\\Cache\\Backend\\RedisBackend';

$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_pagesection']['options'] = array('defaultLifetime' => 3600, 'database' => 3);

$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_hash']['backend'] = 'TYPO3\\CMS\\Core\\Cache\\Backend\\RedisBackend';

$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_hash']['options'] = array('defaultLifetime' => 3600, 'database' => 4);

$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_rootline']['backend'] = 'TYPO3\\CMS\\Core\\Cache\\Backend\\RedisBackend';

$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_rootline']['options'] = array('defaultLifetime' => 3600, 'database' => 5);

$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extbase_object']['backend'] = 'TYPO3\\CMS\\Core\\Cache\\Backend\\RedisBackend';

$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extbase_object']['options'] = array('defaultLifetime' => 3600, 'database' => 6);

#$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extbase_reflection']['backend'] = 'TYPO3\\CMS\\Core\\Cache\\Backend\\RedisBackend';

#$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extbase_reflection']['options'] = array('defaultLifetime' => 3600, 'database' => 7);

}

Über die defaultLifetime kann man natürlich diskutieren. Wichtig ist, dass auch der TYPO3 Scheduler Job zum Cache-Aufräumen integriert ist.

Mehr wichtige Infos dazu: https://docs.typo3.org/typo3cms/CoreApiReference/CachingFramework/Index.html

Was ginge noch?

Ich glaube, man kann noch an sehr vielen Stellen rumschrauben. Ein Test wäre z.B. die Extension nc_staticfilecache wert oder auch, einen Varnish Cache [http://de.slideshare.net/OliverThiele1/typo3-und-varnish] einzurichten.

Fazit

Wir konnten mit vielen kleinen Maßnahmen die Performance erheblich steigern. Den größten Sprung brachten uns aber die Cachesysteme.

Ich würde mich über Feedback freuen, man kann doch immer noch mehr rausholen. Wer mehr zu den Arbeiten erfahren möchte, kann gerne die Kommentarfunktion oder meine Mailadresse schmechel[at]ppw.de nutzen.

Zum Schluss noch eine Zahl als Motivation: Durch diese Maßnahme konnten wir eine Seite von 1,1 auf 0,5 Sekunden Auslieferungszeit bringen!