← Tutti gli articoli

Linux large folios possono causare picchi di scrittura su disco in Galera

Linux large folios possono causare picchi di scrittura su disco in Galera

I picchi di scrittura su disco in Galera possono verificarsi quando i kernel Linux moderni eseguono il flush di ampie sezioni di un file di cache mappato in memoria, anche se il database ha modificato solo una piccola quantità di dati. Percona ha ricondotto questo comportamento a PXC, un cluster basato sul database relazionale utilizzato da molte applicazioni web e che impiega la replica sincrona Galera, dopo un aggiornamento da PXC 5.7 a 8.0.

Il workload e le impostazioni del database server non erano cambiati, eppure ogni membro del cluster ha iniziato a produrre occasionali ma regolari raffiche di intense scritture su disco. Percona ha utilizzato pidstat, che segnala l’attività per processo o thread, e iostat, che misura l’attività dello storage, per stabilire che il processo del database server fosse l’unico responsabile. Le fonti principali erano il receiver della replica Galera, i thread di connessione sul writer node e i thread applier della replica sui membri secondari. Le scritture provenienti dal transactional storage engine e dal binary log rimanevano decisamente troppo ridotte per spiegare il totale.

Durante una raffica durata pochi secondi, i thread applier di Galera hanno generato 13,0 GB, pari al 61% delle scritture. Il receiver galera_recv-0 ha prodotto 5,2 GB, pari al 24%. I page cleaner del transactional storage engine hanno scritto 2,0 GB, il writer del redo log 0,76 GB e il service thread di Galera 0,29 GB. Nonostante sembrassero esserci diversi gigabyte di write sets replicati, cioè modifiche delle transazioni raggruppate e inviate tra i nodi, l’attività delle pagine del transactional storage engine è rimasta stabile.

Una teoria iniziale riguardava binlog_row_image=full. Questa impostazione può fare in modo che gli eventi delle righe includano grandi colonne BLOB, TEXT o JSON anche quando una transazione modifica una sola colonna, e il formato row image si applica ai write sets di Galera oltre che ai binary log. L’analisi con binlogsum non ha confermato questa spiegazione: il volume del binary log era moderato, stabile e non correlato alle raffiche. Anche una ricerca delle modifiche al plugin Galera e alle estensioni di replica wsrep non ha individuato nulla che spiegasse il comportamento.

Il cambiamento significativo riguardava il sistema operativo. Debian 11 utilizzava la serie di kernel Linux 5.10 LTS, mentre Debian 12 ha introdotto Linux 6.1 LTS. Il sistema interessato memorizzava inoltre la cache di Galera su XFS. A differenza della maggior parte dei file di dati e di log del database server, fatta eccezione per lo storage TempTable, i file di cache di Galera utilizzano mmap(), che mappa un file in memoria affinché un’applicazione possa modificarlo come memoria anziché richiamare write() o pwrite() per ogni modifica.

Linux ha introdotto i page folios nella versione 5.16 per gestire in modo più efficiente gruppi di pagine di memoria. I large folios sono arrivati nella page cache di XFS con il kernel 5.18, diventando quindi rilevanti per il passaggio da Linux 5.10 a 6.1. La page cache è la memoria utilizzata da Linux per conservare i dati dei file prima di leggerli nuovamente o di scriverne le modifiche sullo storage. Le segnalazioni di I/O inaspettatamente intenso proveniente dal journal di systemd, un altro utilizzatore di mmap(), descrivono sintomi correlati; una segnalazione di systemd tratta il problema, sebbene Percona affermi che la causa sottostante venga ancora spesso fraintesa in quella comunità.

Con i large folios abilitati, le pagine dei file presenti nella cache possono essere raggruppate in unità comprese tra 128 kB e 2 MB. Nei kernel dalla versione 5.18 alla 6.5, potevano essere interessati anche i percorsi write() e pwrite(). Il transactional storage engine apre comunemente i tablespace con O_DIRECT, che bypassa la page cache, mentre i redo log e i binary log utilizzano piccole operazioni di append che creano folios order-0 da 4 kB. Linux 6.6 ha aggiunto il dirty tracking dei blocchi del filesystem per write() e pwrite(), consentendo al kernel di registrare i blocchi sovrapposti con la granularità dei blocchi del filesystem. Questo miglioramento non si applica agli aggiornamenti mmap(), che continuano a contrassegnare un intero folio. Quando successivamente il writeback copia sul disco i dati dirty presenti nella cache, una modifica di 4 kB può quindi causare la scrittura di ben 2 MB.

Anche la tempistica è coerente con le regole di writeback di Linux. A ogni intervallo dirty_writeback_centisecs, pari per impostazione predefinita a cinque secondi, il kernel verifica se i dati dirty sono sufficientemente vecchi secondo dirty_expire_centisecs, il cui valore predefinito è 30 secondi. Le raffiche osservate si verificavano all’incirca ogni 33 secondi, sebbene tali impostazioni non garantiscano una cadenza fissa. Il readahead è un’altra variabile importante: le impostazioni optimal_io_size e read_ahead_kb di un dispositivo influenzano la dimensione del folio. Modifiche casuali distribuite su molti folios generano un’amplificazione molto maggiore rispetto a più modifiche all’interno di un singolo folio.

Il design di Galera rende il fenomeno particolarmente visibile. La sua gcache è sempre stata mappata in memoria e ha una dimensione predefinita di 128 MB, anche se gli amministratori spesso la ampliano per conservare una cronologia sufficiente per l’Incremental State Transfer (IST), che permette a un nodo che rientra nel cluster di ricevere solo le transazioni che ha perso. I nuovi write sets vengono aggiunti in sequenza, ma numerosi aggiornamenti piccoli e sparsi contrassegnano le transazioni applicate come RELEASED e disponibili per il riutilizzo. Quando il ring buffer ricomincia dall’inizio, anche il relativo allocator procede in avanti ed elimina le aree rilasciate. All’avvio, il recovery esegue per impostazione predefinita una scansione sequenziale dell’intera cache, riempiendo potenzialmente ampie aree della page cache.

La configurazione dello storage può amplificare il problema. Linux può aumentare automaticamente il readahead per il software RAID in base alla geometria dell’array e alla dimensione ottimale di I/O dichiarata; l’hardware RAID e gli stack device-mapper o Logical Volume Manager possono comportarsi in modo analogo. È quanto accaduto nel caso esaminato. Un sistema che utilizza il consueto readahead da 128 kB può subire un’amplificazione sufficiente da essere scambiata per normale traffico del database, mentre folios che raggiungono i 2 MB possono produrre raffiche evidenti che coinvolgono i file galera.cache e gcache.page.X.

Percona afferma che al momento non esiste una soluzione lato kernel per il percorso mmap() ed elenca diverse possibili soluzioni alternative. EXT4 può evitare l’amplificazione dovuta ai large folios sui kernel meno recenti applicabili, perché il relativo supporto è arrivato nella versione 6.16, molto più tardi rispetto al supporto XFS introdotto nella 5.18; il passaggio a EXT4 ha risolto il caso esaminato. Gli amministratori possono ridurre il readahead del dispositivo, accettando possibili costi in termini di prestazioni, oppure gli sviluppatori possono applicare MADV_RANDOM tramite madvise() per disabilitare il readahead per l’accesso mmap casuale. Un’applicazione può sostituire mmap() con pwrite() su Linux 6.6 o versioni successive. Anche un kernel moderno personalizzato compilato senza CONFIG_TRANSPARENT_HUGEPAGE impedisce la creazione di large folios, ma la semplice disabilitazione di Transparent Huge Pages in GRUB non è sufficiente. Percona ha registrato il problema specifico di PXC come PXC-5340.

I controlli dovrebbero riguardare XFS su Linux 5.18 o versioni successive ed ext4 sulla versione 6.16 o successive. Gli amministratori possono esaminare /sys/block//queue/read_ahead_kb e optimal_io_size, cercare FilePmdMapped in /proc/meminfo oppure la voce gcache in smaps e monitorare thp_file_mapped in /proc/vmstat. iostat può mostrare raffiche approssimativamente ogni 30-35 secondi, mentre pidstat -d può attribuire le scritture ai thread Galera in multipli che possono raggiungere i 2 MB. Percona ha inoltre segnalato un caso distinto in cui la combinazione delle scritture nella page cache con O_DIRECT ha causato stalli in un motore di database key-value, dimostrando che le interazioni con i large folios vanno oltre Galera.

Disponibile anche in: EnglishDeutsch