Die Generalprobe vor dem TYPO3-13-Umschaltabend: vier stille Fallen, die erst beim Durchspielen auffallen
Warum wir den TYPO3-13-Wechsel von VINUM erst proben und dann umschalten: vier Fallen, die nicht abbrechen, sondern still falsche Ergebnisse liefern.
Die Generalprobe vor dem Umschaltabend
Im Beitrag „TYPO3 12 auf 13 ohne Big Bang” haben wir beschrieben, wie wir die internationale Weinplattform VINUM in dual-kompatiblen Arbeitspaketen auf TYPO3 13 vorbereitet haben. Der eigentliche Versionswechsel sollte danach nur noch ein kleiner Handgriff sein. Für den Code stimmt das. Für alles, was am Umschaltabend außerhalb des Codes passiert, galt es nicht.
Bevor wir die Produktion umschalten, haben wir den Wechsel deshalb vollständig durchgespielt: jeden heiklen Fensterschritt einzeln auf einer Wegwerfkopie, danach den kompletten Ablauf auf der Staging-Umgebung unter TYPO3 13. Dabei sind vier Fallen aufgetaucht, die in keinem Upgrade-Guide stehen. Sie haben eines gemeinsam: Keine davon hätte laut abgebrochen. Alle hätten still falsche Suchergebnisse, stundenlange Verzögerungen oder Schreibzugriffe auf Produktivsysteme erzeugt. Das ist genau die Art Fehler, die ein kurzer Funktionstest nach dem Go-live übersieht.
Vorweg, damit nichts falsch verstanden wird: Der Produktionswechsel ist zum Zeitpunkt dieses Beitrags noch nicht erfolgt. Staging läuft auf TYPO3 13, die Abnahme dort ist im Gange. Dieser Beitrag handelt von der Vorbereitung und davon, warum sie sich gelohnt hat.
Die Herausforderung
Ein Upgrade-Plan beschreibt, was sich ändern soll. Er beschreibt selten, was eine bestehende Umgebung mit jahrelang gewachsenem Zustand daraus macht:
- Persistente Daten überleben den Code. Suchindex, Datenbank, Container-Volumes und Scheduler-Einträge haben ihren eigenen Stand. Sie reagieren auf ein neues Image anders als eine frisch aufgesetzte Testinstallation.
- Der Ablauf war verstreut. Die Schritte für das Umschaltfenster standen an mindestens fünf Stellen: in Tickets, in einem Solr-Runbook, als Kommentar im Container-Startskript und in einer Smoke-Test-Liste. Drei davon widersprachen sich.
- Es gibt keinen Wartungsmodus. Die Seite lässt sich nicht einfach abschalten. Das Fenster besteht also aus Änderungen an einer laufenden Seite. Die verkehrsarme Zeit verkleinert das Publikum jedes Übergangs, sie schließt es aber nicht aus.
- Die Testumgebung war selbst nicht vertrauenswürdig. Wer auf Staging probt, muss wissen, wie weit Staging von der Produktion entfernt ist und ob ein Test dort wirklich folgenlos bleibt.
Unsere Lösung
Für die Generalprobe galt eine einfache Regel: Jedes Kommando wird wörtlich ausgeführt, Ausgabe und Laufzeit werden danebengeschrieben. Was sich nicht ausführen ließ, wird ausdrücklich als „nicht erprobt” markiert. Jede Zahl wird gegen den aktuellen Stand neu hergeleitet und nicht aus einem älteren Ticket übernommen. Das klingt pedantisch. Genau so sind aber die folgenden vier Fallen ans Licht gekommen.
1. Falle Solr: Der Image-Tausch bewirkt nichts, und niemand beschwert sich
Laut Plan war der Wechsel der Suchmaschine ein Einzeiler: das Apache-Solr-Image von EXT:solr 12.1 auf 13.x heben. Beim Durchspielen zeigte sich, dass das auf einer bestehenden Umgebung gar nichts bewirkt:
- Konfigurationssätze (Configsets) und Cores liegen in einem persistenten Docker-Volume. Docker befüllt dieses Volume genau einmal aus dem Image, nämlich bei seiner Erzeugung, und danach nie wieder. Das neue Configset aus dem neuen Image erreicht ein bestehendes Volume also nie.
- Das Skript, das die Cores anlegt, hat vorhandene Cores bisher einfach übersprungen. Einen Configset-Wechsel an einem bestehenden Core sah es gar nicht vor.
- Selbst der Name stimmte nicht. Das Configset folgt der Minor-Version: Das eingesetzte Image 13.1 liefert
ext_solr_13_1_0und nicht dasext_solr_13_0_0, das in allen Planungsdokumenten stand.
Tückisch ist, wie sich der Fehler zeigt. Auf einer Wegwerfkopie nachgestellt, beantwortete das neue Solr-Image Anfragen an Cores mit dem alten Schema anstandslos: keine Initialisierungsfehler, keine einzige Fehlerzeile im Solr-Log. Die Suche wäre weitergelaufen, nur eben gegen das alte Schema und mit schiefen Ergebnissen.
Die Lösung: Das Core-Skript vergleicht jetzt Configset, Schema und Core-Namen mit den Sollwerten und führt einen Wechsel selbst durch. Für jeden Zustand schreibt es eine eindeutige Markierung ins Log. Fehlt das neue Configset im Volume, fasst es nichts an, und die Suche bleibt verfügbar. Vor allem aber wird der alte Index beim Wechsel archiviert statt gelöscht. Geht es zurück auf die alte Version, holt das Skript ihn wieder hervor, und die Suche ist sofort wieder da, ohne stundenlangen Neuaufbau.
Geprobt haben wir das nicht an den echten Cores, sondern in mehreren Durchläufen auf einem Wegwerf-Volume. Die Dokumentzahlen je Core waren absichtlich unterschiedlich gewählt, damit ein falsch zurückgeholtes Archiv sofort auffällt. Nach dem nächsten regulären Deploy haben wir auf der Produktion nachgesehen: fünf Cores, fünfmal „bereits korrekt”, und die Dokumentzahlen stimmten Wert für Wert mit dem Stand davor überein.
2. Falle Vollindex: Ein Neuaufbau verändert das Suchergebnis dauerhaft
Ursprünglich war geplant, den Suchindex im Umschaltfenster komplett neu aufzubauen. Die Suche hätte dabei „vorübergehend unvollständige Ergebnisse” geliefert. Die Generalprobe hat diese Annahme gleich zweimal widerlegt.
Erstens die Dauer. Die Schätzung rechnete mit den rund 48.000 Einträgen, die im laufenden Betrieb in der Indexierungs-Warteschlange stehen. Ein Vollindex erzeugt aber gut 356.000 Einträge, also das 7,4-Fache. Mit den gemessenen Durchsatzraten wäre die Weinsuche nicht ein, zwei Stunden unvollständig gewesen, sondern bis weit in den nächsten Tag hinein.
Zweitens, und das wiegt schwerer, das Ergebnis. Auf dem frisch indizierten Staging lieferte die Weinsuche nach „Merlot” 920 Treffer, auf der Produktion 1.270. Die Ursache war nicht TYPO3 13, sondern eine Altlast: Degustationen ohne Veröffentlichungsdatum erhalten im Index ein Platzhalter-Datum im Jahr 2222 und gelten damit als noch nicht veröffentlicht. Im gewachsenen Produktionsindex betrifft das 994 Dokumente je Core, ein frisch aufgebauter Index erzeugt 28.620 davon. Unterm Strich wären rund 28 % der öffentlichen Degustationsnotizen still aus der Suche verschwunden. Niemand hätte die fehlenden Treffer mit dem Upgrade in Verbindung gebracht.
Deshalb ist die Mitnahme des bestehenden Index Voraussetzung und keine Option. Möglich ist sie, weil sich das Schema von EXT:solr 13.1 bis auf seine Namenszeilen nicht von dem der Version 12.1 unterscheidet und ein neuer Core den alten Index nachweislich lesen kann. Wie mit den undatierten Altbeständen umgegangen wird, ist eine fachliche Entscheidung. Sie gehört vor jeden künftigen Vollindex und darf nicht als Nebenwirkung eines Upgrade-Abends passieren.
3. Falle Referenzindex: 13,5 Stunden wegen 27 fehlender Datenbankindizes
In TYPO3 13 ist ein Neuaufbau des Referenzindex Pflicht. Die Tabelle bekommt neue Spalten, und das Frontend liest sie jetzt selbst, um Seiteneigenschaften aufzulösen. Ein halb gefüllter Referenzindex ist damit mehr als ein Schönheitsfehler im Backend.
Die erste Messung auf einer produktionsnahen Datenkopie war ernüchternd: hochgerechnet rund 13,5 Stunden. Die Ursache lag nicht in TYPO3, sondern im Datenbankschema. Der Referenzindex löst jede Verknüpfung eines Datensatzes über die Rückverweis-Spalte der verknüpften Tabelle auf, und 27 dieser Spalten hatten keinen Index. Jede Abfrage lief damit durch die komplette Tabelle, einmal pro Datensatz. Allein für die Tabelle der Frontend-Benutzer kamen so rund 10 Milliarden Zeilenzugriffe zusammen.
Drei der fehlenden Indizes waren nicht einmal vergessen, sondern falsch definiert. Sie waren nach der Spalte benannt, die sie abdecken sollten, lagen aber tatsächlich auf der Seiten-ID (pid). Das war ein Überbleibsel, das älter ist als die heutige Versionsgeschichte des Projekts.
Die Lösung war rein additiv: 27 neue Indizes, ausgeliefert mit einem normalen Release und ohne Wartungsfenster. Die beiden aufwendigsten brauchten zusammen rund fünf Sekunden. Die Hochrechnung sank auf 2,7 Stunden, gemessen unter TYPO3 13 auf Staging waren es 2 Stunden 53 Minuten. Weil dieselben Tabellendurchläufe auch beim Speichern betroffener Datensätze anfallen, profitiert das Backend schon heute unter TYPO3 12 davon.
Drei weitere Erkenntnisse aus diesem Schritt:
- Knapp drei Stunden sind zu lang für das Fenster. Der Neuaufbau läuft deshalb entkoppelt im Anschluss. Am Ende wird der Seiten-Cache geleert, weil TYPO3 falsch aufgelöste Seiteneigenschaften sonst bis zu 30 Tage im Cache behält.
- Der Lauf endet mit einer langen, stillen Phase. Zum Schluss entfernt TYPO3 in einer einzigen Anweisung verwaiste Einträge. Auf der Produktion sind das über 18 Millionen Zeilen einer längst entfernten Formular-Erweiterung, 78 % der Tabelle. Wer das nicht weiß, hält diese Phase für einen Hänger und bricht den Lauf ab.
- Der erste Staging-Lauf brach nach sechs Minuten mit Speichermangel ab. Der naheliegende Schluss „zu wenig Arbeitsspeicher” war falsch. Die Staging-Daten vom April enthielten noch eine längst behobene Datenverdopplung: über 316.000 Dateiverweise an einer einzigen Seite, während die Produktion höchstens 18 hat. Ein alter Datenabzug reproduzierte also einen Fehler, den die Produktion gar nicht mehr hat, und der Befund sah aus wie ein Upgrade-Problem.
4. Falle Staging: Die Testumgebung schreibt in die Produktion
Die Smoke-Checkliste für die Abnahme prüft ausdrücklich Registrierung, Newsletter und Abo-Bestellung. Bei der Bestandsaufnahme vor dem Staging-Lauf fiel auf: Das Deploy-Rezept gab Staging dieselben Zugangsdaten für die Marketing-Automation Mautic wie der Live-Seite. Für Datenbank und Mailserver gab es eigene Staging-Werte, für Mautic nicht.
Dass bis dahin nichts passiert war, lag nur daran, dass die Hintergrund-Tasks auf Staging größtenteils stillgelegt waren. Der für die Abnahme vorgesehene Daten-Refresh hätte das geändert. Er bringt den Scheduler-Stand der Produktion mit, und innerhalb einer Minute wären 26 Tasks mit produktiven Zugangsdaten angelaufen. Ein Abnahmetest hätte echte Kontakte angelegt. Eine scheinbar harmlose Aufgabe hätte außerdem eine Export-Mail mit Neuabonnenten an einen Vertriebspartner verschickt, und der bucht jede Zeile daraus als Abo. Dieser Schreibzugriff nach draußen sieht aus wie eine gewöhnliche Mail und wäre bei der Frage „Welche Schnittstelle schreibt wohin?” leicht durchgerutscht.
Die Lösung ist ein Schreib-Guard im Code, der unabhängig vom Zustand des Schedulers greift. Schreibende Zugriffe auf Mautic und der Versand an Partner sind nur erlaubt, wenn der Anwendungskontext exakt Production lautet. Das ist bewusst eine Allow-List. Eine Sperrliste nach dem Muster „nicht in der Produktion” hätte versagt, denn der Staging-Kontext Production/Staging gilt in TYPO3 ebenfalls als Produktion. Die Aussagekraft der Abnahme bleibt trotzdem erhalten: Die Einträge in der Warteschlange entstehen weiterhin und belegen, dass die Strecke gelaufen ist. Nur der Versand unterbleibt.
„Wir haben nichts angefasst” ist allerdings keine Messung. Nachgewiesen wird die Bedingung deshalb über die Zugriffe pro Absenderadresse in den Serverlogs von Mautic: vor und nach jedem Staging-Schritt null Anfragen von Staging. Beim Vorbereiten der Formulartests fiel dann eine zweite Lücke auf. Die direkten Bestätigungsmails der Formulare liefen am Guard vorbei, eine Test-Abobestellung wäre zum Beispiel im Bestellpostfach des Partners gelandet. Die Konsequenz ist grundsätzlicher: Außerhalb des exakten Produktionskontexts verlassen Mails den Server künftig gar nicht mehr, sondern landen in einer lokalen Datei. Das Prinzip bleibt dasselbe: ausdrücklich freigeben, was erlaubt ist, statt einzelne Wege zu sperren. Einen davon übersieht man sonst immer.
5. Nebenbei: eine Umgebung, die seit Mai eingefroren war
Bevor auf Staging überhaupt geprobt werden konnte, musste Staging erst wieder funktionieren. Die Systemplatte war zu 100 % voll, von 75 GB waren noch 9,9 MB frei. Allein 23,5 GB davon waren verwaiste Redis-Snapshot-Dateien. Redis war auf 512 MB konfiguriert, lief aber in einem auf 256 MB begrenzten Container, sodass jeder Speicherversuch abbrach und eine Zwischendatei zurückließ. Dazu kam ein nicht rotiertes Log von 17,6 GB, in das jeder dieser Fehler seinen Stacktrace schrieb.
Die Ursache war seit Ende Mai im Repository behoben. Der Fix ließ sich aber nur per Deploy ausliefern, und für den Deploy fehlte der Platz. Seit dem letzten gescheiterten Deploy am 23. Mai stand die Umgebung still, zuletzt über 1.000 Commits hinter dem aktuellen Stand. Bemerkt hatte es niemand, weil Staging keine Plattenüberwachung hatte.
Daraus haben wir zwei Regeln für die Generalprobe abgeleitet:
- Erst die Basis, dann der Wechsel. Staging wurde zuerst auf den aktuellen Stand unter TYPO3 12 gebracht und als gesunde Basislinie vermessen. Erst danach kam TYPO3 13. Sonst hätte jede Abweichung sowohl aus vier Monaten Entwicklung als auch aus dem Versionswechsel stammen können, und niemand hätte sie zuordnen können.
- Staging wird überwacht wie die Produktion. Die stündliche Plattenprüfung ist jetzt auch auf Staging Teil des Deploys.
6. Das Ergebnis der Probe: ein Runbook statt fünf Teilabläufen
Alles, was die Generalprobe zutage gefördert hat, steht jetzt in einem Runbook für das Umschaltfenster. Es ersetzt die fünf teils widersprüchlichen Teilabläufe:
- Vorbedingungen und Reihenfolge mit Quittierung: Jeder Schritt nennt sein Kommando, die erwartete Ausgabe, die gemessene Laufzeit und ein klares Abbruchkriterium. Was sich nicht vorab proben ließ, ist als „nicht erprobt” gekennzeichnet, zusammen mit der Angabe, woher die Zahl kommen wird.
- Ein ausformulierter Rollback: Code zurück, Datenbank aus der Sicherung unmittelbar vor dem Fenster, Suchindex aus dem Archiv. Beim Ausformulieren fiel auf, dass die Datenbanksicherung den Referenzindex nur als leere Tabellenstruktur enthält. Ein Rollback hätte also unbemerkt eine zweite Baustelle aufgemacht. Der Neuaufbau steht deshalb jetzt als Pflichtschritt im Rückweg.
- Ein gemessenes Zeitfenster: Sieben Tage Serverlogs mit rund 75 Millionen Anfragen zeigen die verkehrsärmste Zeit zwischen 01:00 und 04:00 Uhr. In diesen Zeitraum fallen allerdings zwei nächtliche Backup-Jobs. Das Fenster ist deshalb so gelegt, dass es sich mit keinem der beiden überschneidet. Die Sicherung für das Fenster landet in einem eigenen Verzeichnis, damit der nächtliche Job sie nicht überschreibt.
- Kein zweites Go/No-Go unter Last: Entschieden wird auf Staging. Der Bestätigungslauf auf der Produktion ist bewusst klein und prüft nur, was Staging grundsätzlich nicht zeigen kann. Schlägt er fehl, wird zurückgerollt, statt unter Last nach dem Fehler zu suchen.
Das Ergebnis
Stand heute läuft Staging auf TYPO3 13.4, die Abnahme nach der Smoke-Checkliste ist im Gange, und die Produktion ist noch nicht umgestellt. Die Generalprobe hat trotzdem schon einiges gebracht:
- Keine stille Verfälschung der Suche: Der Solr-Wechsel ist geprobt, der alte Index wird mitgenommen statt verworfen, und der Rückweg dauert Sekunden statt Stunden.
- Eine bewusste Entscheidung statt eines Nebeneffekts: Wie undatierte Altbestände in der Suche behandelt werden, wird fachlich entschieden und nicht von einem Vollindex.
- Ein deutlich kürzerer Referenzindex-Lauf: statt hochgerechnet 13,5 Stunden gemessen knapp 3 Stunden, und ein schnelleres Backend schon vor dem Upgrade.
- Eine Testumgebung, die nichts Echtes anfasst: nachgewiesen durch Messung, nicht bloß angenommen.
- Ein Runbook, das sich im Fenster Schritt für Schritt abarbeiten lässt, mit ausformuliertem Rückweg.
Fazit
Ein Upgrade-Plan beantwortet die Frage, was sich ändern soll. Die Generalprobe zeigt, was eine gewachsene Umgebung tatsächlich daraus macht. Beides unterscheidet sich gerade dort, wo es wehtut: bei persistenten Daten, bei Schnittstellen nach außen und bei Laufzeiten auf echten Datenmengen. Die gefährlichsten Fehler eines Versionswechsels sind nicht die, die abbrechen, sondern die, die still weiterlaufen.
Deshalb gilt für uns: Ein Umschaltabend wird geprobt und nicht nur geplant. Jedes Kommando wird einmal wörtlich ausgeführt, jede Zahl gemessen und jede Schnittstelle auf ihre Richtung geprüft. Und bevor die Probe beginnt, kommt die Testumgebung selbst auf den Prüfstand.
Steht bei Ihnen ein TYPO3-Major-Upgrade an, oder betreiben Sie eine gewachsene Installation mit Suche, Schnittstellen und großen Datenbeständen? Sprechen Sie mit uns – wir bereiten den Wechsel so vor, dass der Umschaltabend keine Überraschungen mehr bereithält.
Über den Autor
Christopher Zechendorf
Christopher Zechendorf leitet die ext.dev GmbH und bringt über 25 Jahre Erfahrung in Webentwicklung, CMS-Systemen und Infrastruktur mit.