Multi-Instanz-Unterstützung

Typo3 in drei Schritten redundant aufsetzen

| Autor / Redakteur: Markus Sternberg, Roman Schenk, Martin Peranic * / Stephan Augsten

Das Open-Source-CMS Typo3 lässt sich mit ein paar Kniffen Multi-Instanz-fähig machen.
Das Open-Source-CMS Typo3 lässt sich mit ein paar Kniffen Multi-Instanz-fähig machen. (Bild: Typo3)

Das Content-Management-System Typo3 ist nach eigenen Aussagen ein Enterprise-CMS, allerdings fehlt eine entscheidende Enterprise-Funktion: die Multi-Instanz-Fähigkeit. Wie Typo3 trotzdem auf mehreren Instanzen aufgesetzt werden kann, stellen drei Entwickler von der Digitalagentur Neofonie in einer How-to Anleitung vor.

Enterprise-Content-Management- oder kurz ECM-Systeme müssen die Anforderungen an ein breites Funktionsspektrum genauso erfüllen, wie die der Ausfallsicherheit und einer hohen Performance – so die wiederkehrende Erwartungshaltung von Neofonie-Kunden. Gewährleistet wird dies in der Regel durch redundante Systeme und eine Lastverteilung auf mehreren Instanzen.

Das CMS Typo3, welches bei vielen Webprojekten zum Einsatz kommt, lässt sich allerdings in der Standard-Installation nicht in einer Load-Balanced-Umgebung betreiben. Dadurch ist u.a. keine Ausfallsicherheit gewährleistet, ebenso drohen Performance-Probleme bei hohen Zugriffszahlen. Darüber hinaus besteht bei einer solchen Installation keine Trennung zwischen Redaktions-und Auslieferungs-Server: Eine Instanz ist immer für beides zuständig, was ein Risiko für Integrität des Contents darstellt.

Im Folgenden soll eine Möglichkeit aufgezeigt werden, wie multiple Typo3-Instanzen aufgesetzt werden können. Alle verwendeten Technologien sind bewährt sowie Open Source und stehen auf gängigen Systemen zur Verfügung.

1.Datenbank-Replikation

Nach alter Manier aktivieren wir das MySQL Binlog für die Master/Slave-Replikation.

Dump der MasterDB

Zum initialen Start benötigen wir den aktuellen Stand vom Backend. Die Slaves setzen bei zukünftigen Deployments auf diesen Stand auf. Wir verwenden Mysqldump mit der Option --single-transaction (StorageEngine InnoDB), um die MasterDB nicht zu blockieren.

mysqldump -h$DB_MASTER_HOST -P$DB_MASTER_PORT -u$DB_REPL_USER -p$DB_REPL_PASS --single-transaction -B $DB_NAME | mysql

Löschen lokaler Cashes

Da später unter anderem die Cache-Tabellen nicht repliziert werden (duplicate entries), müssen wir diese für einen konsistenten Stand der Slaves beim Deployment löschen:

mysql -Nse 'show tables like "cf_%"' typo3db | while read table; do mysql -e "truncate table $table" typo3dbBinlog Information

Wir benötigen „file“ und „position“ des Masters:

MASTER_LOG_FILE=$(mysql -h$DB_MASTER_HOST -P$DB_MASTER_PORT -u$DB_REPL_USER -p$DB_REPL_PASS -e "show master status\G" |grep File |awk '{ print $2 }')

MASTER_LOG_POS=$(mysql -h$DB_MASTER_HOST -P$DB_MASTER_PORT -u$DB_REPL_USER -p$DB_REPL_PASS -e "show master status\G" |grep Position |awk '{ print $2 }')

Excluden bestimmter Tabellen

Um „duplicate entries“ zu vermeiden, replizieren wir alles mit Ausnahme der folgenden Tabellen:

replicate_wild_ignore_table = 'typo3db.cf_%, typo3db.fe_session%,
typo3db.sys_log, typo3db.tx_realurl_urldata, typo3db.tx_realurl_pathdata,
typo3db.sys_file_processedfile'

Replikation dann erneut wie folgt starten:

mysql -e "stop slave;"

mysql -e "CHANGE MASTER TO MASTER_LOG_FILE='$MASTER_LOG_FILE', MASTER_LOG_POS=$MASTER_LOG_POS, MASTER_HOST='$DB_MASTER_HOST', MASTER_PORT=$DB_MASTER_PORT, MASTER_USER='$DB_REPL_USER', MASTER_PASSWORD='$DB_REPL_PASS';"

mysql -e "set global replicate_wild_ignore_table = 'typo3db.cf_%, typo3db.fe_session%, typo3db.sys_log, typo3db.tx_realurl_urldata, typo3db.tx_realurl_pathdata, typo3db.sys_file_processedfile'"

mysql -e "start slave;"

2. Datei-Replikation

Neben einer fehlerfreien Datenbank Replikation muss auch ein zuverlässiger Dateiaustausch stattfinden. Nach der offiziellen Typo3-Dokumentation sind dabei folgende Verzeichnisse und Dateien für uns relevant:

/typo3temp/
typo3conf/PackageStates.php
typo3conf/ext/
typo3conf/l10n/
/fileadmin/
/uploads/

Richtet man sich nach dem klassischen Backend/Frontend-Modell, in der das Frontend read-only ist, reicht es aus, die Datei-Replikation nur in eine Richtung stattfinden zu lassen, und zwar vom Backend zum Frontend. Dies kann exemplarisch mit einem als cronjob laufenden rsync implementiert werden.

Bei dieser Art Setup ist unbedingt darauf zu achten, dass die oben erwähnte Ordner/Dateiliste eingehalten wird. Das Frontend fährt sonst nicht richtig hoch. Interessant dabei ist das typo3temp-Verzeichnis. Offenbar ist es für Typo3 nicht weiter schädlich, wenn sich dort zur Laufzeit Dateien verändern.

Nachteil eines rsync-basierenden Systems ist eine Verzögerung zwischen der Darstellung auf dem Backend und dem Frontend. Dies ist dem periodisch laufenden cronjob geschuldet. Als Grenzfall können dadurch auch tote Datenbankeinträge auf den Frontends entstehen, z. B. wenn der Kopierbefehl fehlschlägt, nachdem die Datenbank bereits repliziert ist.

Möchte man solche Szenarien verhindern, muss auf einen cronjob verzichtet werden. Ein NFS kommt auch nicht infrage, da auf dem Frontend generierte Daten unter keinerlei Umständen auf das Backend gelangen dürfen. Vorstellbar wäre also eine Kombination aus rsyncd und inotify. In diesem Fall werden Dateien direkt beim Erstellen mit rsync auf das Zielsystem kopiert.

3. RelURL Extension

Die von Typo3 generierten URLs sind weder für den Menschen noch für die Suchmaschinen sonderlich schön. Diese werden daher üblicherweise mit der realurl Extension, dem De-facto-Standard für dieses Problem, „hübsch“ gemacht. Dabei erfolgt ein Mapping von /page/tree/path/to/page auf /index.php?id=42 und vice versa.

Damit der Page-Tree nicht bei jedem Request und jedem Rendering eines Links erneut traversiert werden muss, werden die bereits erfolgreich durchgeführten Mappings -nach dem ersten Request auf eine bestimmte URL bzw. nach dem ersten Rendering eines bestimmten Links -in Cache-Tabellen abgelegt. Diese sind:

  • cf_cache_rootline
  • cf_rootline_tags
  • tx_realurl_pathdata
  • tx_realurl_urldata

Wie oben beschrieben müssen die Cache-Tabellen von der Datenbank-Replikation ausgenommen werden, da es ansonsten zu Duplicate-Entries kommt. Von Zeit zu Zeit müssen jedoch einzelne Einträge in diesen Tabellen entfernt werden: wenn sich der Page-Tree oder der Page-Titel, und damit die URL-Struktur, ändert.

Diese werden dann beim nächsten Request bzw. bei der nächsten Link-Generierung durch die Extension neu erzeugt. Das Invalidieren (Löschen) der Cache-Einträge auf dem Backend wird durch die Extension vorgenommen, durch die deaktivierte DB-Replikation kommen diese Änderungen jedoch nicht auf den Frontends an – die URLs haben weiterhin die alte Struktur.

Voraussetzung: Backend vs. Frontend

Auf der jeweiligen Umgebung (Server) muss Typo3 die Information zur Verfügung gestellt werden, ob es Deliver-Frontend oder Redaktions-Backend ist.Das Problem lässt sich mit Bordmitteln (T3 + DB-Replikation) so lösen:

   1. es wird eine Transfer-Tabelle erstellt

   2. es wird ein TCE-Hook für das Cache-Postprocessing gebaut

      – dieser befüllt auf dem Backend die Transfer-Tabelle

   3. es wird ein TSFE-Hook für connectToDB gebaut

      – dieser liest auf den Frontends die Tabelle und löscht die Caches

3.1 Transfer-Tabelle

Die Struktur ist sehr simpel:

CREATE TABLE tx_foo_invalid_cache_on_delivery (
   id INT NOT NULL AUTO_INCREMENT,
   table_name varchar(255) DEFAULT '' NOT NULL,
   inserted TIMESTAMP DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (id)
);

Darin werden alle Cache-Tabellen gespeichert die auf den Frontends geleert werden sollen, dies sind hier die 4oben genannten. Die Tabelle muss mit in die DB-Replikation aufgenommen werden

3.2 TCE-Hook auf dem Backend

Es muss ein Hook für das ClearCache-Postprocessing registriert werden:

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'][] = 'Foo\\Hook\\T3libTcemainHook->clearCachePostProc';

Der Hook darf nur auf dem Backend-System die oben genannte Tabelle befüllen.

if($isDelivery) {
   return;
}

In die Tabelle werden, Komma-separiert, die Namen der vier Cache-Tabellen eingefügt:

$cacheTablesToInvalidate = 'cf_cache_rootline,cf_rootline_tags,tx_realurl_pathdata,tx_realurl_urldata';
$databaseConnection->exec_INSERTquery(
   'tx_crefoportal_invalid_cache_on_delivery',
   [
   'table_name' => $cacheTablesToInvalidate
   ]
);

Fertig. Nach dem INSERT wird der neue Eintrag zu den Frontends repliziert.

3.3 TSFE-Hook auf den Frontends

Dieser wird als Hook für connectToDB registriert:

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['connectToDB'][] = 'Foo\\Hook\\IndexTsHook->preprocessRequest';

Dieser darf nur auf dem Frontend-System die oben genannte Tabelle auslesen:

if(!$isDelivery) {
   return;
}
$rows = $databaseConnection->exec_SELECTgetRows(
   'table_name',
   'tx_crefoportal_invalid_cache_on_delivery',
   ''
);

Die ausgelesenen Tabellen-Namen werden gesplittet und anschließend die jeweiligen Tabellen geleert:

foreach($rows as $row) {
   $tables = $row['table_name'];
   $tables = explode(',',$tables);
   foreach($tables as $table) {
      $databaseConnection->exec_TRUNCATEquery($table);
   }
}

Abschließend wird die Transfer-Tabelle geleert, damit diese nicht zu groß wird:

$databaseConnection->exec_TRUNCATEquery('tx_crefoportal_invalid_cache_on_delivery');

Beim nächsten Request / Linkgenerierung werden nun die entsprechenden Einträge generiert und in die Tabellen geschrieben. Die transfer-Tabelle auf dem Backend-System sollte regelmäßig durch einen Job geleert werden.

* Markus Sternberg ist System Operator und beschäftigt sich mit allen Themen der Hochverfügbarkeit im 24x7 Umfeld. Roman Schenk arbeitet als System Engineer und entwickelt auf Linux basierende Server-Lösungen. Martin Peranic ist Senior-Softwareentwickler und hat mehr als zehn Jahre Erfahrung mit Java und Enterprise-Content-Management-Systemen. Alle drei Autoren sind bei Neofonie tätig.

Kommentare werden geladen....

Kommentar zu diesem Artikel

Anonym mitdiskutieren oder einloggen Anmelden

Avatar
Zur Wahrung unserer Interessen speichern wir zusätzlich zu den o.g. Informationen die IP-Adresse. Dies dient ausschließlich dem Zweck, dass Sie als Urheber des Kommentars identifiziert werden können. Rechtliche Grundlage ist die Wahrung berechtigter Interessen gem. Art 6 Abs 1 lit. f) DSGVO.
  1. Avatar
    Avatar
    Bearbeitet von am
    Bearbeitet von am
    1. Avatar
      Avatar
      Bearbeitet von am
      Bearbeitet von am

Kommentare werden geladen....

Kommentar melden

Melden Sie diesen Kommentar, wenn dieser nicht den Richtlinien entspricht.

Kommentar Freigeben

Der untenstehende Text wird an den Kommentator gesendet, falls dieser eine Email-hinterlegt hat.

Freigabe entfernen

Der untenstehende Text wird an den Kommentator gesendet, falls dieser eine Email-hinterlegt hat.

copyright

Dieser Beitrag ist urheberrechtlich geschützt. Sie wollen ihn für Ihre Zwecke verwenden? Infos finden Sie unter www.mycontentfactory.de (ID: 45119315 / Web Apps)