Selektives pt-online-schema-change kann Galera-Stalls auslösen
Ein selektiver WHERE-Filter in pt-online-schema-change kann einen Produktionsstillstand auf einem Galera-basierten Cluster der Open-Source-relationalen Datenbank auslösen, wie ein detaillierter Blogbeitrag vom 28. September 2026 von Corrado Pandiani beschreibt. Der Beitrag schildert einen Kundeneinsatz mit einer geclusterten Version dieser Datenbank (oft als Galera-Cluster bezeichnet), bei dem eine routinemäßige Online-Schemaänderung, die nur die neuesten Zeilen kopierte, zu schwerer Galera-Flusskontrolle, hohem Overhead und einem Cluster führte, der nach Dutzenden Minuten Stillstand neu gestartet werden musste. Die Ursache war nicht die Schemaänderung selbst, sondern das Zusammenspiel von adaptiver Chunk-Größenanpassung, hochselektivem Kopieren der neuesten Zeilen, Cluster-Replikation und InnoDB-Checkpointing.
Das Szenario beginnt mit einer großen Tabelle mit Hunderten Millionen Zeilen. Statt die gesamte Tabelle neu aufzubauen, wollte das Team nur eine Teilmenge der Zeilen kopieren und einen neuen Index hinzufügen. Der Befehl sah so aus: pt-online-schema-change --alter "ADD INDEX idx_status(status)" --where "created_at >= NOW() - INTERVAL 30 DAY" D=test,t=events --execute --force. Einfach ausgedrückt ist pt-online-schema-change (pt-osc) ein Tool, das die Struktur einer Tabelle ändert, während die ursprüngliche Tabelle weiterhin den Datenverkehr bedient, und die Option --where begrenzt die Arbeit auf Zeilen, deren created_at-Datum innerhalb der letzten 30 Tage liegt. Dieser Ansatz ist üblich, wenn historische Daten ignoriert werden können, nur aktive Datensätze geändert werden müssen oder eine Migration gestaffelt wird, um die Gesamtzeit zu reduzieren.
Normalerweise passt die Kopierphase von pt-osc die Größe jedes Zeilen-Chunks an, um die Arbeit nahe an einer konfigurierten Ausführungszeit zu halten, mit einem Standardwert von 0,5 Sekunden. Wenn Chunks zu schnell abgeschlossen werden, erhöht das Tool die nächste Chunk-Größe; wenn Chunks langsamer werden, verringert es die Größe. Diese adaptive Chunk-Größenanpassung funktioniert gut bei Tabellen mit relativ gleichmäßiger Zeilendichte, da jeder Chunk eine ähnliche Mischung aus zu kopierenden und zu überspringenden Zeilen enthält. Das Problem tritt auf, wenn die meisten gescannten Zeilen durch eine selektive --where-Bedingung verworfen werden. Im Beispiel hatte die Tabelle 1 Milliarde Zeilen: 990 Millionen entsprachen nicht dem Filter und nur 10 Millionen taten es. Die passenden Zeilen befanden sich am Ende des geclusterten Index, da die created_at-Werte mit dem Primärschlüssel anstiegen und die Primärschlüsselgrenzen mit der WHERE-Bedingung kombiniert wurden. Lange Zeit scannte pt-osc Chunks, in denen fast jede Zeile abgelehnt wurde, was die Kopieroperation extrem schnell machte. Der adaptive Algorithmus interpretierte diese Geschwindigkeit als "Chunks sind zu klein" und erhöhte die Chunk-Größe immer weiter. Als der Scan die ersten passenden Zeilen erreichte, war die Chunk-Größe dramatisch gewachsen, sodass pt-osc statt einiger tausend Zeilen plötzlich Hunderttausende oder sogar eine Million Zeilen in einer einzigen Transaktion kopieren konnte.
Wenn diese übergroße Transaktion auf einen Galera-Cluster trifft, verschiebt sich das Problem von einem ruhigen Scan zu einem Replikationssturm. Galera ist eine synchrone Replikationstechnologie, die mehrere Datenbankknoten identisch hält und jeden kopierten Chunk als Write-Set repliziert, also die Gruppe von Zeilenänderungen, die an die anderen Knoten gesendet wird. Sehr große Transaktionen erzeugen sehr große Write-Sets, lange Zertifizierungsphasen (der Prozess, bei dem Knoten prüfen, dass die Schreibvorgänge nicht kollidieren), erhöhte Apply-Warteschlangen, längere Replikationslatenz und letztlich die Aktivierung der Flusskontrolle. Die Flusskontrolle ist Galeras eingebauter Mechanismus, um Schreibvorgänge auf einem schnellen Knoten zu pausieren, wenn andere Knoten zurückfallen. Sobald sie startet, sinkt der Cluster-Durchsatz stark, Anwendungs-Commits beginnen zu warten, und in extremen Fällen erscheint der Cluster fast eingefroren, bis jeder Knoten die übergroße Transaktion vollständig angewendet hat. Der Beitrag stellt fest, dass der adaptive Algorithmus, der eigentlich den Durchsatz optimieren soll, ironischerweise genau das Arbeitslastmuster erzeugt, das Galera am wenigsten mag.
InnoDB, die Standard-Storage-Engine der Open-Source-relationalen Datenbank, leidet ebenfalls. Sobald die ersten großen Chunks verarbeitet wurden, zeigte das Fehlerprotokoll des Writer-Knotens eine Warnung wie "[Warning] [MY-014084] [InnoDB] Threads are unable to reserve space in redo log ... Consider increasing innodb_redo_log_capacity." Das Redo-Log ist eine Aufzeichnung von Änderungen, die zur Wiederherstellung nach einem Absturz verwendet wird, und wenn eine sehr große Transaktion eintrifft, können Schreib-Threads nicht genügend freien Speicherplatz finden, weil der log_checkpointer-Verbraucher zurückfällt. In der Praxis zwingt dies den Server, Checkpoints häufiger und in größerem Umfang auszulösen, was zusätzlichen Overhead verursacht. Nachdem Galera das Write-Set auf die anderen Knoten repliziert hatte, erschien dieselbe Art von Meldung auf diesen Knoten während der Apply-Phase. Typische Symptome sind ein schnell ansteigender Flusskontroll-Prozentsatz, eine wachsende wsrep_local_recv_queue (die Warteschlange der lokal anzuwendenden Schreibvorgänge), hohe Replikationsverzögerung, wartende Anwendungs-Commits, höhere CPU-Auslastung, große Spitzen in der Transaktionsanwendungszeit und häufigere InnoDB-Checkpoints auf allen Knoten. Die Schemaänderung kann zwar abgeschlossen werden, aber der Produktionsverkehr kann stark beeinträchtigt werden; im schlimmsten beschriebenen Fall blieb der Cluster stehen und musste neu gestartet werden.
Der erste und effektivste vorgeschlagene Fix besteht darin, die adaptive Chunk-Größenanpassung zu deaktivieren, wenn eine selektive --where-Klausel verwendet wird. Statt die Chunk-Größen kontinuierlich zu erhöhen, sollten sie während der gesamten Operation fest bleiben, indem --chunk-time = 0 und --max-flow-ctl = 0 in den Befehl aufgenommen werden. Das Setzen von --chunk-time auf null stoppt die automatische Anpassung der Chunk-Größe durch pt-osc, sodass die Abfragezeiten variieren, die Chunk-Größen jedoch nicht. Eine Alternative besteht darin, explizit einen Wert für --chunk-size anzugeben und --chunk-time wegzulassen. Wenn der adaptive Algorithmus umgangen wird, wird die Chunk-Ausführung vorhersehbar, die Transaktionsgröße bleibt begrenzt, und Galera erhält niemals unerwartet massive Write-Sets. Die gesamte Schemaänderung kann etwas länger dauern, aber die Cluster-Stabilität verbessert sich dramatisch, was in der Produktion normalerweise der bevorzugte Kompromiss ist.
Ein weiterer zu berücksichtigender Parameter ist --max-flow-ctl. Mit --max-flow-ctl=PCT prüft pt-osc regelmäßig wsrep_flow_control_paused, den Prozentsatz der Zeit, die der Knoten pausiert für die Flusskontrolle verbracht hat, und pausiert automatisch das Zeilenkopieren, wenn dieser Prozentsatz den Schwellenwert überschreitet, und setzt fort, sobald der Cluster wieder darunter fällt. Das Setzen von --max-flow-ctl auf null (oder sehr nahe daran, z. B. 1) lässt pt-osc das Kopieren von Zeilen beim ersten Anzeichen stoppen, dass ein Knoten in die Flusskontrolle eingetreten ist, anstatt eine gewisse Pausenzeit zu tolerieren, bevor es zurückweicht. Die Analyse nennt dies die sicherste mögliche Haltung für einen Produktionscluster, insbesondere einen, der bereits Checkpointer-Lag-Warnungen zeigt, da jeder zusätzliche Schreibdruck durch das chunkweise Kopieren der Migration einen bereits kämpfenden Knoten in einen viel größeren Stillstand kippen könnte. Der nahezu null Schwellenwert tauscht Migrationsgeschwindigkeit gegen Sicherheit und lässt das Tool sich der Echtzeit-Kapazität des Clusters unterordnen und nur dann voranschreiten, wenn wirklich keine Konflikte bestehen. Für kritische, latenzempfindliche Produktionsarbeitslasten ist eine langsamere, aber sichere Schemaänderung besser als eine schnelle, die ein clusterweites Einfrieren der Schreibvorgänge riskiert.
Ein verwandter Hebel ist --chunk-index. Standardmäßig chunked pt-online-schema-change die Tabelle anhand des Primärschlüssels oder des am besten geeigneten eindeutigen Index, weshalb die Chunk-Grenzen im Kundenfall derselben monoton steigenden Spalte wie created_at folgten und die lange Strecke fast leerer Chunks erzeugten. Wenn die Tabelle einen sekundären Index hat, dessen Reihenfolge nicht mit created_at korreliert, kann das Erzwingen des Chunkens auf diesem Index mit --chunk-index=idx_name passende und nicht passende Zeilen gleichmäßiger über die Chunks verteilen, sodass der adaptive Algorithmus nie die ausgedehnte Phase niedriger Dichte sieht, die die Chunk-Größe auf unsichere Werte treibt. Der Beitrag warnt jedoch, dass dies kein Ersatz für --chunk-time=0 und --max-flow-ctl ist, da ein schlecht gewählter Chunking-Index die Leistung beeinträchtigen kann und nur wenige Tabellen einen geeigneten Index haben, der sowohl selektiv genug zum Chunken als auch unkorreliert mit der --where-Bedingung ist. In der Praxis ist --chunk-index eine sekundäre, tabellenspezifische Optimierung.
Eine dritte Option besteht darin, die --where-Klausel ganz zu vermeiden und die Aufgabe in zwei Phasen aufzuteilen. Zuerst pt-archiver ausführen, um die nicht mehr benötigten Zeilen zu löschen, dann pt-online-schema-change ausführen, um die Tabelle zu ändern. Dieses zweistufige Verfahren vermeidet jedes Risiko, das aus der ungleichmäßigen Verteilung der passenden Zeilen entsteht. Der Beitrag kommt zu dem Schluss, dass pt-online-schema-change eines der besten Tools für Online-Schema-Migrationen bleibt, aber bei Verwendung von --where, um nur eine kleine Teilmenge der Zeilen auf einem Galera-basierten Cluster der Open-Source-relationalen Datenbank zu kopieren, kann die adaptive Chunk-Größenanpassung unbeabsichtigt übergroße Transaktionen erzeugen, die übermäßige Galera-Flusskontrolle auslösen und den Cluster vorübergehend blockieren. Das Festhalten der Chunk-Größen beseitigt diese Rückkopplungsschleife, was zu gleichmäßigerem Replikationsverhalten und geringerem Betriebsrisiko führt. Weitere Fixes sind ebenfalls verfügbar, und die zugrunde liegende Lektion ist, dass Vorhersehbarkeit manchmal eine bessere Optimierung ist als Aggressivität. Für Teams, die diese betriebliche Last lieber auslagern möchten, bieten Managed-Database-Anbieter wie AEU Data (aeu-data.com) Überwachung, automatisierte Backups und Hochverfügbarkeitskonfiguration, die Betreibern helfen können, die hier beschriebene Art von Replikationsstillstand zu erkennen und sich davon zu erholen.