...

MariaDB Undo Logs: Hintergrundwissen für Administratoren

MariaDB Undo steuert, wie InnoDB alte Zeilenversionen speichert, Rollbacks sicher ausführt und konsistente Lesesichten liefert, während Schreibvorgänge laufen. Ich zeige, wie Undo Logs mit History List und Purge zusammenspielen, warum lange Transaktionen Speicher fesseln und wie ich das Wachstum der Undo-Bereiche kontrolliere.

Zentrale Punkte

  • MVCC und konsistente Reads: Undo speichert alte Versionen, Leser blockieren nicht.
  • History List: Commits reihen Historie ein, Purge baut ab.
  • Lange Transaktionen: Halten alte Versionen, treiben Speicher und Latenzen.
  • Konfiguration: Undo-Tablespaces, Purge-Threads, Truncate steuern Wachstum.
  • Monitoring: History-Länge, Transaktionsalter, Undo-Größen früh prüfen.

Wie Undo Logs MVCC ermöglichen

Ich starte mit dem Kern: Jede Änderung schreibt die vorherige Zeilenversion in den Undo-Log, damit ein konsistenter Snapshot weiter gültig bleibt. Leser greifen auf die passende ältere Version zu, während Schreiber neue Daten ablegen und Indizes aktualisieren; so bleibt Parallelität hoch. Zeilen verketten ihre Vorgänger, bis Purge sie löschen darf. Ohne diese Kette würden Rollbacks fehlen und Lesesichten kippen. Genau hier liefert Undo die Brücke zwischen Transaktionssicherheit, Isolation und belastbaren Lesezugriffen.

Interne Struktur der Undo Logs

Unter der Haube unterscheide ich vor allem zwei Undo-Spielarten: Insert-Undo und Update-Undo. Insert-Undo erlaubt es, noch nicht bestätigte Einfügungen rückgängig zu machen. Update-Undo hält ältere Versionen bei Änderungen oder Lösch-Markierungen vor, damit Snapshots weiter funktionieren. InnoDB markiert gelöschte Zeilen zunächst nur als entfernt (Delete-Mark) und verzögert die tatsächliche Entsorgung, bis kein Snapshot sie mehr sehen kann. Diese Trennung ist entscheidend: Rollbacks brauchen präzise Vorher-Zustände, während konsistente Leser eine Version finden müssen, die logisch zu ihrem Startzeitpunkt passt. Deswegen verweisen Zeilen intern auf die vorherige Version, und Indizes tragen Zusatzinformationen, damit Purge später Indexeinträge sauber nachziehen kann.

History List, Purge und Speicher

Nach jedem Commit landen historische Änderungen in der globalen History List, die der Purge-Thread asynchron abbaut. Kommt Purge nicht hinterher, wächst diese Liste und hält alte Zeilenversionen künstlich am Leben. Das verursacht mehr Lesewege, mehr I/O und größere Undo-Tablespaces. Ich prüfe in solchen Lagen immer Isolationsstufen und offene Snapshots, denn eine ungünstige Wahl der Isolation erhöht die Lebensdauer alter Versionen. Wer Purge-Tempo, History-Länge und aktive Transaktionen zusammendenkt, erkennt Engpässe früh und bremst Speicherdrift, bevor sie kritisch wird.

Purge-Mechanik und Tuning-Optionen

Purge arbeitet best effort: Es sammelt bereinigbare Einträge aus der History List, entfernt Delete-Marks endgültig, aktualisiert Sekundärindizes und gibt Undo-Bereiche frei. In Systemen mit hoher Änderungsrate skaliere ich die Parallelität (z. B. über mehrere Purge-Worker) und justiere die Batching-Strategie, damit Purge stetig, aber nicht aggressiv läuft. Faustregeln:

  • Kurze, konstante Batches statt seltener Großläufe – das glättet I/O und Checkpoints.
  • Purge nicht gegen Speicher oder Log-Flushing ausspielen: Beide Wege müssen mithalten.
  • Lange Snapshots zuerst auflösen, bevor ich Batchgrößen weiter hochdrehe – sonst verpufft der Effekt.

Wichtig: Purge ist kein Ersatz für gute Transaktionsdisziplin. Selbst mit hoher Parallelität bleibt Undo gebunden, solange alte Snapshots existieren. Ich beobachte daher Purge-Fortschritt und Transaktionsalter zusammen und korrigiere die Arbeitslast, wenn Purge permanent hinterherhinkt.

Konfiguration der Undo Tablespaces

Undo-Informationen können je nach Setup im System-Tablespace oder in separaten Undo-Tablespaces liegen. Ich trenne Undo gern aus, um Wachstum und I/O besser zu kontrollieren. Viele Installationen erlauben dynamisches Wachstum, teils inklusive Rückgabe von Platz per Truncate. Das klingt komfortabel, erhöht jedoch die Pflicht zum Monitoring, weil lange Snapshots eine schnelle Schrumpfung verhindern. Ich wähle Speicherort, Größe und Purge-Parallelität so, dass Änderungsraten und Zeitfenster im Alltag sauber abgefangen werden und Wiederherstellung nicht leidet.

Einstellung Wirkung Hinweis
innodb_undo_directory Speicherort für Undo-Dateien Getrennte Datenträger entkoppeln I/O
innodb_purge_threads Mehr Purge-Worker für Abbau Bei hoher Änderungsrate erhöhen
innodb_undo_log_truncate Gibt ungenutzten Platz zurück Nur wirksam, wenn History frei ist
innodb_max_undo_log_size Grenzwert für Wachstum Verfügbarkeit je nach Version

Speicherlayout und Filesystem-Aspekte

Separierte Undo-Tablespaces bringe ich bevorzugt auf schnelle SSDs, getrennt von Daten- und Log-I/O. Unterstützt das Filesystem TRIM/Discard, kann ein Truncate Speicher physisch an das Betriebssystem zurückgeben. Ich plane dennoch mit konservativen Obergrenzen, weil Platzfreigabe nicht garantiert ist, solange Snapshots Undo binden. Auch Kompression auf dem Filesystem lohnt nur, wenn CPU-Spielraum vorhanden ist und Schreibmuster nicht fragmentieren. Wichtig bleibt die Beobachtung von Latenzspitzen: Wächst Undo auf einem ausgelasteten Datenträger, verschärfen sich Write-Amplification und Checkpoint-Druck schleichend.

Monitoring und Diagnose

Ich prüfe regelmäßig die Größe der Undo-Tablespaces, die History List Length und das Alter offener Transaktionen. SHOW ENGINE InnoDB STATUS, Performance-Schema und Information-Schema liefern klare Signale. Wachsen Undo-Bereiche, während Purge wenig abträgt, klemme ich zunächst alte Sessions ab. Zusätzlich schaue ich auf Sperren, denn unnötige Row Locks verlängern Transaktionen und Snapshots. Wer diese Kennzahlen täglich sichtet, verhindert plötzliche I/O-Spitzen und verkürzt Wege im Speicher.

Leistungsfolgen langer Transaktionen

Lange Lese- oder Schreibtransaktionen halten Versionen fest, selbst wenn sie logisch veraltet sind. Das bläht Undo auf, vergrößert Scans und steigert Cache-Druck. Ich reduziere solche Effekte mit kürzeren Batches, konsequentem COMMIT und Timeouts für Sessions. Reports, die stundenlang lesen, laufen besser in kleineren Fenstern oder gegen Replikate. Wer Autocommit klärt, Abfragepläne strafft und Idle-Transaktionen schließt, befreit Purge und entlastet die Instanz.

Rollback-Segmente und Parallelität

Undo-Einträge liegen in Rollback-Segmenten, die gleichsam Slots für gleichzeitig aktive Änderungen bereitstellen. Viele gleichzeitige Writer profitieren von ausreichend Rollback-Segmenten, weil Einfügungen und Updates ihre Undo-Ketten dann seltener teilen müssen. Ich beobachte Wartemuster auf Rollback-Ressourcen und erhöhe deren Anzahl dort, wo Version und Distribution es erlauben. Symptome mangelnder Parallelität sind unerwartete Wartezeiten in ansonsten kurzen Update-Phasen oder stark schwankende Schreiblatenzen unter Last. Mehr Segmente verteilen den Druck, heben aber nicht die Grundregel auf: Lange Snapshots schlagen jedes Tuning.

Isolationsstufen im Detail

Die Isolationsstufe entscheidet, wie lange Undo-Versionen sinnvoll sind. In REPEATABLE READ hält eine Transaktion ihren Start-Snapshot über die gesamte Dauer; Undo bleibt also potenziell sehr lange gebunden. In READ COMMITTED werden Sichtfenster pro Statement gebildet; das verkürzt in vielen Workloads die Lebensdauer alter Versionen deutlich. SELECT … FOR UPDATE und LOCK IN SHARE MODE ziehen Sperren und verändern das Nebenläufigkeitsprofil – nützlich gegen Lost Updates, aber kritisch für Undo, wenn Leser zu lange offen bleiben. Ich setze daher READ COMMITTED gezielt dort ein, wo Reports oder API-Reads konsistente, aber nicht transaktionsweite Sichten benötigen, und bleibe bei REPEATABLE READ, wenn Geschäftslogik es verlangt.

Recovery und Startup-Szenarien

Beim Start nutzt InnoDB die Undo-Informationen, um unvollständige Transaktionen sauber zurückzurollen. Das sorgt für konsistente Sichten, bevor neue Clients arbeiten. In Sonderfällen existieren Startmodi, die Prüfungen abkürzen, doch ich setze sie nur im Notfall ein. Reine Beschleunigung ohne Diagnose rächt sich, weil Integrität Vorrang hat. Wer Recovery-Zeit und Undo-Größen im Blick behält, trifft bessere Entscheidungen über Wartungsfenster und Risiko.

Praxisregeln für Administration

Ich halte Transaktionen kurz, committe häufig und vermeide Lesesessions ohne Ende, damit Purge freie Bahn hat. Größere Massenänderungen teile ich in wohldosierte Batches, damit die History List nicht ansteigt. Purge-Threads skaliere ich mit der Änderungsrate und passe das Undo-Layout an die Speicherhardware an. Zusätzlich dokumentiere ich Geschäftsprozesse, die lange Snapshots benötigen, und plane Zeitfenster bewusst. So bleibt die Undo-Nutzung vorhersagbar und die Latenz niedrig.

Workload-Muster und Tuning

E-Commerce, Reporting und Content-Systeme erzeugen viele Änderungen und brauchen disziplinierte Transaktionen. Ich setze konservative Timeouts für Leser, optimiere Indizes für punktgenaue Updates und limitiere Batch-Größen. Bei hoher Schreiblast erhöhe ich Purge-Parallelität und reguliere Checkpoint-Druck. Außerdem prüfe ich die Schreibrate im Verhältnis zu Transaktionslogs und Recovery, damit Crash-Recovery berechenbar bleibt. Dieses Zusammenspiel hält Undo-Volumen planbar und schützt die Konsistenz.

Backups und Replikation

Logische Backups mit konsistentem Snapshot verlängern die Lebensdauer alter Versionen zwangsweise – Undo wächst, bis das Backup durch ist. Ich plane solche Läufe außerhalb von Hochlastfenstern, drossele gleichzeitige Writer und stelle genügend Purge-Kapazität bereit. Physische Backups können die Undo-Belastung verringern, entbinden aber nicht von der Sorgfalt bei Snapshots. Auf Replikas halte ich Reports bevorzugt im READ COMMITTED und schließe lange Leerlauf-Transaktionen, damit SQL-Apply nicht ins Hintertreffen gerät. Bleibt eine Replika in Verzug, steigt auch dort die Undo-Last, denn das Nachziehen vieler Deletes/Updates produziert eine Welle an Historie, die Purge erst wegarbeiten muss.

Runbook: Undo-Wachstum schnell stoppen

  • Aktive Langläufer identifizieren: Offene Transaktionsdauer und Sitzungen mit großen result sets prüfen.
  • Idle in transaction konsequent beenden: Autocommit prüfen, vergessene Cursors schließen.
  • Purge-Kapazität erhöhen: Zusätzliche Worker aktivieren und Batches moderat vergrößern.
  • Writer-Spitzen glätten: Batchgrößen begrenzen, Micro-Commits einführen.
  • Wartungsfenster nutzen: Große Lösch-/Update-Wellen in planbare Slots verlagern.
  • Nach Stabilisierung: Undo-Truncate erlauben, bis Filesystemgröße wieder zum Bedarf passt.

Kapazitätsplanung für Undo

Ich kalkuliere Undo konservativ aus Änderungsrate, durchschnittlicher Zeilengröße und maximalem Snapshot-Fenster. Eine einfache Näherung: Änderungs-Events pro Sekunde × mittlere Payload × geplantes Sichtfenster in Sekunden. Sicherheitsaufschlag für Index- und Metadaten einrechnen. Diese Faustformel schafft ein Gefühl für Worst-Case-Bedarf und schützt vor Überraschungen, wenn Reporting, Backups oder Migrationsläufe gleichzeitig Snapshots binden. In wachsenden Systemen prüfe ich quartalsweise, ob Workload-Verschiebungen (neue Features, mehr mobile Clients, stärkere Peaks) den Bedarf verändern.

Sonderfälle: Temporäre Tabellen und DDL

Temporäre InnoDB-Tabellen verwenden eigene Bereiche; deren Änderungen belasten das reguläre Undo weniger, können aber bei großen Sorts/Joins dennoch I/O treiben. DDL-Operationen wie ALTER TABLE erzeugen oft massive Änderungswellen – ich spalte sie bei Bedarf in inkrementelle Schritte und plane sie in ruhigen Phasen ein. Auch hier gilt: Kurze, saubere Transaktionen schlagen riskante Abkürzungen. Bricht ein DDL-Lauf ab, hilft Undo, in einen konsistenten Zustand zurückzukehren; dafür braucht es jedoch ausreichend Speicher und Zeit, die ich vorab einplane.

Beispiel: Auswirkungen messen

Ich beginne mit einem Baseline-Snapshot der Undo-Größe, der History-Länge und der mittleren Transaktionsdauer. Danach führe ich gezielte Änderungen durch, etwa das Erhöhen der Purge-Threads oder das Kürzen von Batch-Größen. Anschließend vergleiche ich die Kennzahlen, bis Undo-Wachstum und Latenzen in ein gesundes Verhältnis rutschen. Treffe ich auf Ausreißer, schaue ich in Abfragepläne und Session-Listen, um hängende Leser zu identifizieren. Dieser kreisförmige Ablauf liefert schnelle Erfolge, ohne die Verfügbarkeit zu gefährden.

Häufige Fehlannahmen

Ein Commit löscht alte Versionen nicht sofort; Purge entscheidet erst später. Truncate-Optionen lösen kein grundlegendes Designproblem, wenn Transaktionen zu lange leben. Große Undo-Dateien bedeuten nicht zwingend Korruption, oft blockiert eine einzige Session. Leser blockieren Schreiber zwar selten, doch ungeeignete Abfragen verlängern Snapshots indirekt. Wer diese Irrtümer ausräumt, trifft bessere Entscheidungen und reduziert Stillstände.

Zusammenfassung für Eilige

Undo Logs halten Vergangenheit greifbar, damit InnoDB Transaktionen sicher zurückdreht und Leser konstante Sichten sehen. Ich kontrolliere Wachstum, indem ich Transaktionen straffe, Purge-Threads passend setze und Undo-Tablespaces sinnvoll platziere. Das Monitoring der History-Länge, der Undo-Größen und der Transaktionsalter zeigt Trends früh. Bei Auffälligkeiten prüfe ich Arbeitslast, Sperren und Sitzungen, statt an Symptomen zu drehen. Wer diese Routine pflegt, hält Performance, Konsistenz und Wiederanlauf verlässlich im Griff.

Aktuelle Artikel

NUMA Balancing auf moderner Linux Server Hardware im Rechenzentrum
Server und virtuelle Maschinen

NUMA Balancing in Linux: deaktivieren oder aktiv lassen?

Erfahre, wie NUMA Balancing die Linux Performance auf moderner Server Hardware beeinflusst und wann du das Feature deaktivieren oder aktiv lassen solltest. Fokus: numa balancing.