← Alle Beiträge

Unter Linux können large folios Galera-Schreibspitzen auf Datenträgern auslösen

Unter Linux können large folios Galera-Schreibspitzen auf Datenträgern auslösen

Galera-Schreibspitzen auf Datenträgern können auftreten, wenn moderne Linux-kernel große Abschnitte einer speicherabgebildeten Cache-Datei auf den Datenträger schreiben, obwohl die Datenbank nur eine kleine Datenmenge geändert hat. Percona führte dieses Verhalten bei PXC – einem Cluster, das auf der von vielen Webanwendungen verwendeten relationalen Datenbank basiert und die synchrone Replikation von Galera nutzt – auf ein Upgrade von PXC 5.7 auf 8.0 zurück.

Die Arbeitslast und die Einstellungen des Datenbankservers hatten sich nicht geändert. Dennoch erzeugte jedes Cluster-Mitglied gelegentliche, aber regelmäßige Spitzen mit intensiven Schreibvorgängen auf dem Datenträger. Percona stellte mithilfe von pidstat, das die Aktivität nach Prozess oder Thread meldet, und iostat, das die Speicheraktivität misst, fest, dass ausschließlich der Datenbankserverprozess dafür verantwortlich war. Die Hauptquellen waren der Replikationsempfänger von Galera, Verbindungs-Threads auf dem Writer-node und Replikations-Applier-Threads auf sekundären Mitgliedern. Die Schreibvorgänge der transaktionalen Storage-engine und des binary log blieben bei Weitem zu gering, um die Gesamtmenge zu erklären.

Während einer wenige Sekunden dauernden Spitze entfielen 13,0 GB beziehungsweise 61 % der Schreibvorgänge auf Galera-Applier-Threads. Der Empfänger galera_recv-0 erzeugte 5,2 GB beziehungsweise 24 %. Page-cleaner der transaktionalen Storage-engine schrieben 2,0 GB, der Redo-log-Writer 0,76 GB und der Galera-Service-Thread 0,29 GB. Obwohl es nach mehreren Gigabyte replizierter write sets aussah – also gebündelten Transaktionsänderungen, die zwischen nodes übertragen werden –, blieb die Seitenaktivität der transaktionalen Storage-engine unverändert.

Eine erste Theorie betraf binlog_row_image=full. Diese Einstellung kann dazu führen, dass Row-events große BLOB-, TEXT- oder JSON-Spalten enthalten, selbst wenn eine Transaktion nur eine einzige Spalte ändert. Das Row-image-Format gilt sowohl für Galera-write sets als auch für binary logs. Eine Analyse mit binlogsum stützte diese Erklärung jedoch nicht: Das Volumen des binary log war moderat, konstant und stand in keinem Zusammenhang mit den Spitzen. Auch eine Untersuchung der Änderungen am Galera-plugin und an den wsrep-Replikationserweiterungen ergab nichts, was das Verhalten erklärt hätte.

Die wesentliche Änderung betraf das Betriebssystem. Debian 11 verwendete die Linux-5.10-LTS-kernel-Serie, während Debian 12 Linux 6.1 LTS mitbrachte. Das betroffene System speicherte den Cache von Galera außerdem auf XFS. Anders als die meisten Daten- und Logdateien des Datenbankservers – mit Ausnahme des TempTable-Speichers – verwenden die Cache-Dateien von Galera mmap(). Dabei wird eine Datei in den Speicher abgebildet, sodass eine Anwendung sie wie Arbeitsspeicher verändern kann, statt für jede Änderung write() oder pwrite() aufzurufen.

Linux führte page folios in Version 5.16 ein, um Gruppen von Speicherseiten effizienter als größere Einheit zu verwalten. large folios erreichten mit kernel 5.18 den XFS-page cache und wurden damit für den Wechsel von Linux 5.10 auf 6.1 relevant. Als page cache wird Speicher bezeichnet, den Linux nutzt, um Dateidaten vorzuhalten, bevor sie erneut gelesen oder Änderungen auf den Datenträger geschrieben werden. Berichte über unerwartet hohe I/O-Aktivität beim systemd-journal, das ebenfalls mmap() verwendet, beschreiben ähnliche Symptome. Ein systemd-Issue behandelt das Problem, wobei Percona zufolge die zugrunde liegende Ursache in dieser Community noch immer häufig missverstanden wird.

Wenn large folios aktiviert sind, können im Cache abgelegte Dateiseiten zu Einheiten von 128 kB bis hin zu 2 MB zusammengefasst werden. In den kernels 5.18 bis 6.5 konnten auch die Pfade von write() und pwrite() betroffen sein. Die transaktionale Storage-engine öffnet Tablespaces üblicherweise mit O_DIRECT, wodurch der page cache umgangen wird. Redo-logs und binary logs verwenden dagegen kleine Append-Vorgänge, die order-0 folios von 4 kB erzeugen. Linux 6.6 führte für write() und pwrite() filesystem-block dirty tracking ein. Dadurch kann der kernel überlappende Blöcke mit der Granularität von Dateisystemblöcken erfassen. Diese Verbesserung gilt nicht für Aktualisierungen über mmap(), bei denen weiterhin ein vollständiges folio als geändert markiert wird. Wenn writeback die geänderten Cache-Daten später auf den Datenträger kopiert, kann eine Änderung von 4 kB daher Schreibvorgänge von bis zu 2 MB verursachen.

Auch der zeitliche Ablauf entspricht den Linux-Regeln für writeback. Bei jedem Intervall von dirty_writeback_centisecs – standardmäßig fünf Sekunden – prüft der kernel anhand von dirty_expire_centisecs, standardmäßig 30 Sekunden, ob geänderte Daten alt genug sind. Die beobachteten Spitzen traten ungefähr alle 33 Sekunden auf, auch wenn diese Einstellungen keinen festen Zeitplan garantieren. Eine weitere wichtige Variable ist readahead: Die Einstellungen optimal_io_size und read_ahead_kb eines Geräts beeinflussen die Größe der folios. Zufällige Änderungen, die über viele folios verteilt sind, verursachen eine wesentlich stärkere Schreibverstärkung als mehrere Änderungen innerhalb eines einzelnen folio.

Das Design von Galera macht dieses Verhalten besonders sichtbar. Der gcache war schon immer speicherabgebildet und ist standardmäßig 128 MB groß. Administratoren vergrößern ihn jedoch häufig, damit genügend Verlauf für Incremental State Transfer (IST) erhalten bleibt. Dadurch erhält ein zurückkehrender node nur die Transaktionen, die er verpasst hat. Neue write sets werden sequenziell angehängt, doch zahlreiche kleine, verstreute Aktualisierungen markieren angewandte Transaktionen als RELEASED und damit als wiederverwendbar. Wenn der Ringpuffer umläuft, bewegt sich sein Allocator ebenfalls vorwärts und verwirft freigegebene Bereiche. Beim Start durchsucht die Wiederherstellung standardmäßig den gesamten Cache sequenziell, wodurch möglicherweise große Bereiche des page cache gefüllt werden.

Die Speicheranordnung kann das Problem verstärken. Linux kann readahead bei Software-RAID automatisch entsprechend der Array-Geometrie und der angegebenen optimalen I/O-Größe erhöhen. Hardware-RAID sowie device-mapper- oder Logical Volume Manager-Stacks können sich ähnlich verhalten. Dies war beim untersuchten Fall geschehen. Bei einem System mit dem üblichen readahead von 128 kB kann die Verstärkung gering genug sein, um mit normalem Datenbankverkehr verwechselt zu werden. Erreichen folios dagegen 2 MB, können auffällige Spitzen entstehen, an denen die Dateien galera.cache und gcache.page.X beteiligt sind.

Percona zufolge gibt es derzeit keine kernel-seitige Lösung für den mmap()-Pfad; das Unternehmen nennt jedoch mehrere Workarounds. EXT4 kann die durch large folios verursachte Verstärkung auf den jeweils relevanten älteren kernels vermeiden, da dessen Unterstützung erst mit Version 6.16 und damit deutlich später als die XFS-Unterstützung in Version 5.18 eingeführt wurde. Der Wechsel zu EXT4 löste den untersuchten Fall. Administratoren können das readahead des Geräts reduzieren und dabei mögliche Leistungseinbußen in Kauf nehmen. Entwickler können alternativ über madvise() die Option MADV_RANDOM anwenden, um readahead bei zufälligem mmap-Zugriff zu deaktivieren. Eine Anwendung kann mmap() unter Linux 6.6 oder neuer durch pwrite() ersetzen. Ein eigener moderner kernel, der ohne CONFIG_TRANSPARENT_HUGEPAGE kompiliert wurde, verhindert ebenfalls die Erzeugung von large folios. Das bloße Deaktivieren von Transparent Huge Pages in GRUB reicht jedoch nicht aus. Percona erfasste das PXC-spezifische Problem unter PXC-5340.

Prüfungen sollten XFS unter Linux 5.18 oder neuer sowie ext4 unter Linux 6.16 oder neuer abdecken. Administratoren können /sys/block//queue/read_ahead_kb und optimal_io_size überprüfen, in /proc/meminfo nach FilePmdMapped oder in smaps nach dem gcache-Eintrag suchen und thp_file_mapped in /proc/vmstat beobachten. iostat kann Spitzen in Abständen von etwa 30 bis 35 Sekunden anzeigen, während pidstat -d Schreibvorgänge Galera-Threads zuordnen kann, deren Vielfache bis zu 2 MB groß sind. Percona wies außerdem auf einen separaten Fall hin, bei dem die Kombination von Schreibvorgängen über den page cache mit O_DIRECT zu Verzögerungen in einer Schlüssel-Wert-Datenbank-Engine führte. Dies zeigt, dass die Wechselwirkungen von large folios über Galera hinausreichen.

Auch verfügbar in: EnglishItaliano