Trascrizione della relazione del 2015 di Ilya Kosmodemyansky "Ottimizzazione di Linux per migliorare le prestazioni di PostgreSQL"
Disclaimer: Noterò che questa relazione è datata novembre 2015 — sono passati più di 4 anni e molto tempo è trascorso. La versione discussa nella relazione, 9.4, non è più supportata. Negli ultimi 4 anni sono state rilasciate 5 nuove versioni di PostgreSQL e 15 versioni del kernel Linux. Se riscrivessimo questi punti, otterremmo alla fine una relazione diversa. Ma qui viene trattata l'ottimizzazione fondamentale di Linux per PostgreSQL, che è ancora attuale.


Mi chiamo Ilya Kosmodemyansky. Lavoro per PostgreSQL-Consulting. E ora parlerò un po' di cosa fare con Linux in relazione ai database in generale e a PostgreSQL in particolare, poiché i principi sono piuttosto simili.
Di cosa parleremo? Se interagite con PostgreSQL, è necessario essere in qualche modo un amministratore UNIX. Cosa significa? Se confrontiamo Oracle e PostgreSQL, in Oracle bisogna essere per l'80% DBA dell'amministratore del database e per il 20% amministratore di Linux.
Con PostgreSQL è un po' più complicato. Con PostgreSQL è fondamentale avere una buona comprensione di come funziona Linux. Inoltre, è necessario seguire da vicino gli aggiornamenti, poiché di recente ci sono stati molti sviluppi. Nuovi kernel sono stati rilasciati, sono apparse nuove funzionalità e le prestazioni sono migliorate, ecc.
Perché parliamo di Linux? Non perché siamo alla conferenza Linux di San Pietroburgo, ma perché, nelle condizioni attuali, uno dei sistemi operativi più giustificati per l'uso con database in generale e con PostgreSQL in particolare è Linux. Purtroppo, FreeBSD sta seguendo una direzione piuttosto strana. Ci saranno problemi sia di prestazioni che in molte altre aree. Le prestazioni di PostgreSQL su Windows sono un tema a parte, legato al fatto che Windows non ha la memoria condivisa come UNIX, mentre PostgreSQL dipende molto da questo, poiché è un sistema multi-processo.
E esotismi come Solaris, penso interessino in misura minore, quindi procediamo.

Una moderna distribuzione Linux ha più di 1.000 parametri syctl, a seconda di come viene costruito il kernel. Inoltre, se consideriamo diverse opzioni, ci sono molti modi per ottimizzare ulteriormente il sistema. Esistono parametri per i file system, e modalità per il loro montaggio. Se ci sono domande su come avviare il sistema, come attivare le impostazioni nel BIOS, o come configurare l'hardware, ecc.
Si tratta di un argomento molto ampio, che potrebbe richiedere giorni per essere trattato, piuttosto che un breve intervento, ma ora mi concentrerò su aspetti importanti su come evitare le insidie che sicuramente comprometteranno l'ottimizzazione del database su Linux, se non vengono sistemate. Inoltre, c'è un aspetto importante: molti parametri sono di default impostati in modo non corretto per i database. Cioè, funzionerà male o non funzionerà affatto.

Quali sono i tradizionali obiettivi di tuning in Linux? Credo che, dato che tutti voi avete a che fare con l'amministrazione di Linux, non sia necessario spiegare cosa siano gli obiettivi.
Si può ottimizzare:
- CPU.
- Memoria.
- Storage.
- Altro. Di questo parleremo alla fine come un dessert. Anche, ad esempio, parametri come la politica di risparmio energetico possono influenzare le prestazioni in modo molto imprevedibile e poco piacevole.

Qual è la specificità di PostgreSQL e dei database in generale? Il problema è che non si può semplicemente regolare un singolo dado e aspettarsi un miglioramento significativo delle prestazioni.
Sì, ci sono questi dadi, ma i database sono complessi. Interagiscono con tutte le risorse del server e preferiscono interagire completamente. Se guardate alle raccomandazioni moderne di Oracle su come utilizzare il sistema operativo host, è un po' come la barzelletta del cosmonauta mongolo: dare da mangiare al cane e non toccare nulla. Diamo al database tutte le risorse, e il database si gestirà da solo.
In linea di principio, la situazione con PostgreSQL è molto simile. La differenza è che il database non riesce a prelevare autonomamente tutte le risorse, cioè è necessario gestire tutto a livello di Linux.
L'idea principale non è selezionare un singolo target e iniziare a modificarlo, ad esempio la memoria, la CPU o qualcosa del genere, ma analizzare il carico di lavoro e cercare di ottimizzare al massimo la larghezza di banda in modo che il carico che i bravi programmatori ci hanno creato, compresi i nostri utenti, attraversi il nostro database nel modo più efficiente possibile.

Ecco un'immagine che spiega cosa sia. C'è un buffer del sistema operativo Linux, c'è la memoria condivisa e ci sono i buffer condivisi di PostgreSQL. A differenza di Oracle, PostgreSQL funziona esclusivamente attraverso il buffer del kernel, cioè affinché una pagina dal disco entri nella sua memoria condivisa, deve passare attraverso il kernel buffer e la situazione è esattamente la stessa al contrario.
Sotto questo sistema risiedono i dischi. Li ho rappresentati come dischi. In realtà, potrebbe esserci un controller RAID e così via.
E questo input-output avviene in un modo o nell'altro attraverso questo sistema.
PostgreSQL è un database classico. Le sue operazioni avvengono tramite pagine. Utilizziamo le pagine per caricare i blocchi in memoria. Se non succede nulla e le abbiamo semplicemente lette, queste pagine gradualmente escono dalla cache e dai buffer condivisi e ritornano su disco.
Se abbiamo sostituito qualcosa, l'intera pagina viene contrassegnata come sporca. L'ho evidenziata in blu. Ciò significa che questa pagina deve essere sincronizzata con lo storage dei blocchi. Quando la rendiamo sporca, registriamo un'operazione nel WAL. A un certo punto interviene un fenomeno chiamato checkpoint. In questo log viene registrata l'informazione del suo arrivo. Ciò significa che tutte le pagine sporche presenti in quel momento nei buffer condivisi vengono sincronizzate con il disco dello storage tramite fsync attraverso il kernel buffer.
Perché viene fatto? Se perdiamo la corrente, non possiamo permetterci di perdere tutti i dati. La memoria persistente, di cui ci hanno parlato, è al momento solo teoria nei database; è un futuro promettente verso cui aspiriamo e che ci piace, ma attualmente siamo ancora indietro di vent'anni. E, naturalmente, è necessario monitorare tutto questo.
L'obiettivo di massimizzare la larghezza di banda è ottimizzare tutte queste fasi affinché tutto funzioni rapidamente. La memoria condivisa è principalmente una cache basata su pagine. In PostgreSQL, abbiamo inviato una richiesta di selezione e i dati sono stati recuperati dal disco. Sono stati caricati nei buffer condivisi. Pertanto, per migliorare le prestazioni, è necessaria molta memoria.
Affinché tutto funzioni bene e rapidamente, è fondamentale configurare correttamente il sistema operativo in tutte le fasi. Inoltre, bisogna scegliere hardware bilanciato, perché se c'è uno squilibrio in qualche parte, anche se avete molta memoria, il servizio potrebbe risultare lento.
Esamineremo ciascuno di questi punti.

Perché queste pagine viaggino avanti e indietro più velocemente, è necessario raggiungere quanto segue:
- In primo luogo, è necessario lavorare in modo più efficiente con la memoria.
- In secondo luogo, deve essere più efficiente questa transizione, quando le pagine passano dalla memoria al disco.
- E, in terzo luogo, devono esserci buoni dischi.
Se avete 512 GB di memoria RAM in server e tutto questo alla fine arriva su un disco rigido SATA senza alcuna cache, allora l'intero server database non si trasforma solo in una zucca, ma in una zucca con interfaccia SATA. Vi troverete a dover affrontare direttamente questo. E nulla potrà salvarvi.

Per quanto riguarda il primo punto sulla memoria, ci sono tre cose che possono complicare notevolmente la vita.
La prima di esse è il NUMA. Il NUMA è un meccanismo progettato per migliorare le prestazioni. A seconda del carico di lavoro, è possibile ottimizzare diverse cose. E nella sua attuale forma, non è particolarmente efficace per applicazioni come i database che utilizzano intensamente buffer condivisi di page cache.

In poche parole. Come si fa a capire che c'è qualcosa di sbagliato con NUMA? Avete un rumore strano, improvvisamente qualche CPU risulta sovraccarico. Nel frattempo, analizzate le query in PostgreSQL e non notate nulla di simile. Queste query non dovrebbero consumare così intensamente la CPU. Riconoscerlo può richiedere tempo. È più semplice seguire fin dall'inizio la raccomandazione corretta su come configurare NUMA per PostgreSQL.

Cosa succede realmente? NUMA significa Non-Uniform Memory Access. Qual è il concetto? Avete una CPU, e nelle vicinanze c'è la sua memoria locale. E questa memoria interconnects può accedere alla memoria di altre CPU.
Se eseguite numactl --hardware, vedrete un lungo elenco. Tra le varie informazioni ci sarà il campo distances. Ci saranno numeri - 10-20, qualcosa del genere. Questi numeri non sono altro che il numero di hop necessari per connettere e utilizzare questa memoria remota localmente. In generale, è una buona idea. Questo migliora notevolmente le prestazioni in alcune situazioni di carico.
Immaginate di avere una CPU che prima cerca di utilizzare la propria memoria locale e poi tenta di accedere a un'altra memoria tramite interconnect per qualche operazione. E a questa CPU arriva tutto il vostro page cache di PostgreSQL – tutto, per un certo numero di gigabyte. Riceverete sempre il caso peggiore, perché di solito c'è poca memoria direttamente in questo modulo. E tutta la memoria gestita passa attraverso questi interconnect. Risultato: lentissimo e frustrante. E la CPU che gestisce questo nodo è costantemente sovraccarica. I tempi di accesso a questa memoria sono scarsi, lenti. È proprio la situazione che non desiderate se utilizzate questo per un database.
Pertanto, la soluzione più corretta per un database è che il sistema operativo Linux non sappia affatto cosa stia succedendo. Deve accedere alla memoria come sarebbe normale.
Perché ciò? Apparirebbe logico il contrario. Questo succede per un motivo molto semplice: abbiamo bisogno di molta memoria per il page cache – decine, centinaia di gigabyte.
E se abbiamo evidenziato e memorizzato nella cache i nostri dati, allora il vantaggio dell'uso della cache sarà significativamente maggiore rispetto ai benefici di un accesso alla memoria così astuto. In questo modo avremo un guadagno non comparabile rispetto a quella che sarà una gestione più efficace della memoria utilizzando NUMA.
Pertanto, attualmente ci sono due approcci, finché non arriverà un futuro luminoso in cui il database non saprà autonomamente su quali CPU sta lavorando e da dove deve prelevare i dati.

Dunque, l'approccio corretto è disabilitare completamente NUMA, ad esempio, al riavvio. Nella maggior parte dei casi, i guadagni sono così significativi che non si pone nemmeno la questione di quale sia la soluzione migliore.
C'è un'altra opzione. La utilizziamo più spesso della prima, perché quando un cliente richiede supporto, riavviare il server è un grande problema per lui. Lì c'è il suo business che gira. E tendono a sperimentare problemi legati a NUMA. Perciò cerchiamo di disattivarlo in modi meno invasivi rispetto al riavvio, ma qui bisogna essere più cauti nel controllare che sia effettivamente disattivato. Perché, come dimostra l'esperienza, disattivare NUMA sul processo principale di PostgreSQL va bene, ma non è affatto garantito che funzioni. È necessario controllare e assicurarsi che sia davvero disattivato.
C'è un buon post di Robert Haas. È uno dei collaboratori di PostgreSQL. Uno dei principali sviluppatori di tutto il funzionamento a basso livello. E se segui i link di questo post, lì vengono raccontate diverse storie colorite su come NUMA abbia complicato la vita alle persone. Guarda, studia la checklist degli amministratori di sistema, che cosa bisogna configurare sul server affinché il nostro database funzioni bene. Queste impostazioni devono essere annotate e controllate, altrimenti la situazione non sarà molto buona.
Vorrei sottolineare che questo riguarda tutte le impostazioni di cui parlerò. Di solito, i database vengono configurati in modalità master-slave per garantire la resilienza. Non dimenticate di applicare queste impostazioni anche sullo slave, perché a un certo punto avrete un guasto e passerete allo slave, che diventerà il master.
In una situazione di emergenza, quando tutto va male, il telefono suonerà continuamente e il capo arriverà con un grosso bastone; non avrete tempo per pensare a controllare. E i risultati potrebbero essere molto deludenti.

Il prossimo punto riguarda le huge pages. È difficile testare le huge pages separatamente, e non ha molto senso farlo, anche se ci sono dei benchmark capaci di farlo. Si trovano facilmente online.
Qual è il punto? Avete un server non molto costoso con molta RAM, ad esempio, più di 30 GB. Non state utilizzando le huge pages. Questo significa che avete sicuramente un overhead nell'uso della memoria. E questo overhead non è affatto piacevole.

Perché succede tutto ciò? E cosa sta accadendo? Il sistema operativo allocca la memoria in piccole porzioni. È comodo e storicamente così. E se entriamo nei dettagli, il SO deve tradurre indirizzi virtuali in fisici. Questo processo non è semplice, quindi il SO memorizza i risultati di questa operazione nella Translation Lookaside Buffer (TLB).
E poiché il TLB è una cache, in questa situazione sorgono tutti i problemi tipici delle cache. In primo luogo, se hai molta memoria RAM e questa è tutta allocata in piccole porzioni, allora questo buffer diventa molto grande. E se la cache è grande, la ricerca in essa diventa più lenta. Il sovraccarico è significativo e occupa spazio, ovvero la memoria operativa consuma ciò che non è corretto. Questo è uno.
Due: più si espande la cache in questa situazione, maggiore è la probabilità di avere cache misses. L'efficienza di questa cache diminuisce rapidamente con l'aumento delle sue dimensioni. Per questo motivo, nei sistemi operativi è stato ideato un approccio semplice. In Linux è utilizzato da tempo. In FreeBSD è comparso non molto tempo fa. Ma stiamo parlando di Linux. Si tratta di huge pages.
È importante notare che l'idea delle huge pages è stata inizialmente promossa da comunità che comprendevano Oracle e IBM, cioè i produttori di database hanno pensato seriamente che ciò sarebbe stato utile anche per i database.

E come collegarlo a PostgreSQL? Innanzitutto, nel kernel di Linux devono essere abilitate le huge pages.
In secondo luogo, devono essere specificate esplicitamente tramite il parametro sysctl – quante sono. I numeri qui provengono da un vecchio server. Puoi calcolare quanti shared buffers hai approssimativamente, affinché le huge pages possano adattarsi.
E se l'intero server è dedicato a PostgreSQL, un buon punto di partenza è assegnare il 25 % della memoria RAM ai shared buffers, oppure il 75 %, se sei sicuro che la tua base di dati ci entrerà. Ecco il primo punto di partenza. Se hai 256 GB di RAM, avrai quindi 64 GB di shared buffers. Calcola approssimativamente con un certo margine – quale dovrebbe essere impostata questa cifra.
Fino alla versione 9.2 (se non sbaglio, dalla versione 8.2) era possibile integrare PostgreSQL con huge pages tramite una libreria di terze parti. E questo è sempre necessario fare. Innanzitutto, è necessario che il kernel sappia allocare correttamente le huge pages. In secondo luogo, l'applicazione che lavora con esse deve essere in grado di utilizzarle. Non può farlo così, senza ulteriori passaggi. Poiché PostgreSQL allocava memoria secondo lo stile system 5, questo poteva essere fatto utilizzando libhugetlbfs — questo è il nome completo della libreria.
Nella versione 9.3 è stata migliorata la gestione della memoria in PostgreSQL e si è abbandonato il metodo system 5 per l'allocazione della memoria. Tutti erano molto felici, perché altrimenti si provava a far funzionare due istanze di PostgreSQL sulla stessa macchina e lui diceva che mancavano memoria condivisa. E diceva che bisognava correggere sysctl. E c'era un tale sysctl che bisognava anche riavviarsi e così via. Insomma, tutti furono contenti. Ma l'allocazione della memoria mmap ha rotto l'uso delle huge pages. La maggior parte dei nostri clienti utilizza grandi shared buffers. E abbiamo fortemente raccomandato di non passare alla 9.3, perché lì l'overhead iniziava a calcolarsi in buoni percentuali.
Tuttavia, la community ha prestato attenzione a questo problema e nella versione 9.4 ha notevolmente migliorato questa funzione. In 9.4 è stato aggiunto un parametro in postgresql.conf, che consente di attivare try, on o off.
Try è il parametro più sicuro. All'avvio di PostgreSQL, quando viene allocata la memoria condivisa, tenta di ottenere da huge pages questa memoria. Se non riesce, torna all'allocazione standard. Se utilizzate FreeBSD o Solaris, potete impostare try, è sempre sicuro.
Se è impostato on, non si avvia semplicemente se non riesce a ottenere da huge pages. Qui entra in gioco la preferenza personale. Ma se utilizzate try, verificate che sia stata effettivamente allocata la memoria corretta, poiché ci sono molte possibilità di errore. Attualmente, questa funzionalità funziona solo su Linux.
Un'ultima nota prima di procedere. Le Transparent huge pages non riguardano PostgreSQL per ora. Non possono essere utilizzate a dovere. Con le Transparent huge pages, per un carico di lavoro che richiede grandi porzioni di memoria condivisa, i vantaggi si manifestano solo con volumi molto elevati. Se hai terabyte di memoria, allora potrebbe avere importanza. Se parliamo di utilizzi più quotidiani, quando hai 32, 64, 128 o 256 GB di memoria sulla macchina, allora le huge pages normali vanno bene, mentre le Transparent possono essere semplicemente disabilitate.

E l'ultima cosa riguardante la memoria, sebbene non direttamente collegata alla larghezza di banda, può complicare molto la situazione. L'intera capacità di trasferimento dati ne risentirà se il server continua a effettuare il swap.
E questo sarà molto sgradevole in diverse situazioni. Il problema principale è che nei kernel moderni il comportamento è leggermente diverso rispetto ai kernel Linux più vecchi. È una questione su cui è difficile mettere i piedi, perché quando parliamo di lavoro con lo swap, finiamo con l'arrivo intempestivo dell'OOM-killer. E avere un OOM-killer che non arriva in tempo e termina PostgreSQL è sgradevole. Questo si riflette su tutti, ovvero fino all'ultimo utente.

Cosa sta succedendo? Hai una grande quantità di memoria RAM, tutto funziona bene. Ma per qualche motivo, il server si blocca nello swap e rallenta a causa di questo. Sembrerebbe che ci sia molta memoria, eppure accade.

Un tempo consigliavamo di impostare vm.swappiness a zero, ovvero di disattivare lo swap. In passato sembrava che 32 GB di RAM e i corrispondenti buffer condivisi fossero una quantità enorme. La funzione principale dello swap è avere uno spazio in cui spingere i dati quando c'è un problema. E questo non veniva più eseguito. E poi, che ne fai di quei dati? È un compito in cui non è chiaro se lo swap sia davvero necessario, specialmente in una quantità così grande.
Ma nelle versioni più moderne del kernel, cioè nelle terze, il comportamento è cambiato. E se si imposta lo swap a zero, cioè si disattiva, prima o poi, anche con un certo quantitativo di memoria RAM rimasta, il processo OOM-killer arriverà per uccidere i consumatori più intensivi. Questo perché considererà che, con un carico di lavoro del genere, ci resta ancora poco e non ucciderà i processi di sistema, ma qualcosa di meno importante. Questo meno importante sarà un consumatore intensivo di memoria condivisa, ovvero il postmaster. E dopo questo sarà un bene se non sarà necessario ripristinare il database.
Quindi, attualmente, se non ricordo male, la maggior parte delle distribuzioni ha un valore predefinito di circa 6, cioè in quale momento iniziare a utilizzare lo swap in base a quanta memoria è rimasta. Attualmente, consigliamo di impostare vm.swappiness = 1, perché praticamente lo disattiva, ma non produce effetti come l'arrivo inaspettato dell'OOM-killer che ha già eliminato tutto.

Cosa succede adesso? Quando parliamo delle performance dei database e ci avviciniamo gradualmente ai dischi, tutti si prendono la testa tra le mani. Perché la verità che i dischi sono lenti e la memoria è veloce è conosciuta da tutti fin dall'infanzia. Tutti sanno che ci saranno problemi di prestazioni del disco nei database.
Il principale problema di prestazioni di PostgreSQL, legato ai picchi dei checkpoint, non è causato dalla lentezza del disco. Piuttosto, deriva dal fatto che la larghezza di banda della memoria e del disco non è bilanciata. Possono essere sbilanciate in diversi modi. PostgreSQL non è configurato correttamente, il sistema operativo non è ottimizzato, l'hardware non è impostato bene e l'hardware è inadeguato. Questo problema non si verifica solo se tutto funziona come dovrebbe, cioè se non ci sono carichi o se le configurazioni e l'hardware sono ben selezionati.

Cos'è e come appare? Di solito, le persone che lavorano con PostgreSQL hanno affrontato questo problema più volte. Lasciate che spieghi. Come accennato, PostgreSQL effettua periodicamente dei checkpoint per trasferire le pagine sporche dalla memoria condivisa al disco. Se abbiamo una grande quantità di memoria condivisa, i checkpoint cominciano a influenzare intensamente il disco, poiché dumpano queste pagine tramite fsync. Arrivano nel buffer del kernel e vengono scritte sui dischi grazie a fsync. E se il volume di questa operazione è elevato, possiamo osservare un effetto indesiderato, ovvero un utilizzo molto elevato dei dischi.
Qui ho due immagini. Ora spiegherò cosa sono. Si tratta di due grafici correlati nel tempo. Il primo grafico mostra l'utilizzo del disco. Qui quasi raggiunge il 90 % in quel momento. Se il vostro database fallisce con dischi fisici e un controller RAID, un utilizzo vicino al 90 % è una brutta notizia. Questo significa che a breve si raggiungerà il 100 % e l'input-output si fermerà.
Se avete un array di dischi, la situazione è un po' diversa. Dipende da come è configurato, che tipo di array si tratta, ecc.
Parallelamente, qui è configurato un grafico da una vista interna di postgres, che mostra come avviene il checkpoint. In verde è evidenziata la quantità di buffer, queste pagine sporche che in questo momento sono arrivate in questo checkpoint per la sincronizzazione. Questa è la cosa principale da sapere. Vediamo che qui sono arrivate molte pagine e a un certo punto siamo rimasti bloccati, cioè abbiamo continuato a scrivere, qui chiaramente il sistema disco è molto occupato. E il nostro checkpoint ha un forte impatto sul disco. Idealmente, la situazione dovrebbe apparire così, cioè qui ci sono stati meno scritti. E possiamo risolvere questo con delle impostazioni, affinché in futuro rimanga così. Cioè, l'utilizzo è ridotto, ma da qualche parte stiamo comunque scrivendo.
Cosa fare per risolvere questo problema? Se si è fermato l'IO sotto il database, significa che tutti gli utenti che sono arrivati per eseguire le loro query dovranno aspettare.

Se guardiamo dal punto di vista di Linux, se hai preso un buon hardware, lo hai configurato correttamente, e hai impostato PostgreSQL in modo che faccia questi checkpoint meno frequentemente, distribuendoli nel tempo, allora si fatica con le impostazioni predefinite di Debian. Per la maggior parte delle distribuzioni Linux, la situazione è così: vm.dirty_ratio=20, vm.dirty_background_ratio=10.
Cosa significa questo? Dalla versione 2.6 del kernel è apparso un demonio per il flushing. Pdglush dipende da chi lo utilizza, ed è responsabile dello svuotamento in background delle pagine sporche dal buffer del kernel e dello svuotamento quando necessario, senza eccezioni per liberare le pagine sporche, quando lo svuotamento in background non è più efficace.
Quando avviene il background? Quando il 10% della memoria RAM totale presente sul server è occupato da pagine sporche nel buffer del kernel, viene chiamata una funzione speciale di scrittura in background. Perché è in background? Essa accetta come parametro quanti page scrivere. E, ad esempio, scrive N pagine. E per un certo periodo di tempo, questa cosa va in pausa. E poi torna e scrive ancora un certo numero di pagine.
È una storia estremamente semplice. La situazione è come quella di una piscina, dove in un tubo si versa e nell'altro si immette. Abbiamo ricevuto un checkpoint e se ha inviato poche pagine sporche per l'eliminazione, queste si assorbiranno gradualmente dal kernel buffer pgflush.
Se queste pagine sporche continuano ad accumularsi, si accumulano fino al 20%, dopodiché il sistema operativo dà priorità per scriverle su disco, perché se si interrompe l'alimentazione, avremo problemi. Ad esempio, perderemo questi dati.
Qual è il trucco? Il trucco consiste nel fatto che questi parametri, nel mondo moderno, del 20 e 10% della totale memoria RAM della macchina, sono totalmente spaventosi dal punto di vista della capacità di qualsiasi sistema di archiviazione che possediate.
Immaginate di avere 128 GB di RAM. 12,8 GB arrivano al vostro sistema di archiviazione. E qualunque cache o array abbiate, non ce la faranno a reggere.

Pertanto, vi consigliamo di impostare immediatamente questi valori in base alle capacità del vostro controller RAID. Qui ho subito fornito una raccomandazione per un controller che ha 512 MB di cache.
È tutto molto semplice. Puoi impostare vm.dirty_background in byte. Queste impostazioni annullano le due precedenti. O utilizzi il ratio di default, oppure se attivi quelli in byte, funzioneranno quelli in byte. Ma poiché sono un consulente DBA e lavoro con diversi clienti, cerco sempre di essere prudente; quindi, se in byte, allora in byte. Nessuno ha garantito che un buon amministratore non aggiunga memoria al server, non lo riavvii, mentre il numero rimane lo stesso. Calcola semplicemente queste cifre, per essere sicuro che tutto ci stia.
Cosa succede se non si riesce a entrare? È scritto che qualsiasi flushing si ferma in modo efficace, ma in realtà è un modo di dire. Il sistema operativo ha un grosso problema: ha molte pagine sporche, quindi si ferma in modo efficace l'IO che generano i vostri clienti, cioè, quando un'applicazione invia una query SQL al database, essa aspetta. Qualsiasi input-output in esso ha la priorità più bassa perché il database è occupato con il checkpoint. E quando finirà non è chiaro. E quando raggiungete uno stato di flushing non in background, significa che tutto il vostro IO è occupato da esso. E finché non termina, non farete nulla.
Ci sono anche altri due punti importanti che vanno oltre questa relazione. Queste impostazioni devono corrispondere alle impostazioni in postgresql.conf, cioè le impostazioni dei checkpoint. E il vostro sistema di dischi deve essere adeguatamente configurato. Se avete una cache su RAID, deve avere una batteria. La gente acquista RAID con una buona cache senza batteria. Se avete SSD in RAID, devono essere server-oriented e devono avere condensatori. Ecco un elenco di controlli dettagliati. A questo link trovi la mia presentazione su come configurare le prestazioni del disco in PostgreSQL. Lì ci sono tutte queste liste di controllo.

Cosa può complicare ulteriormente la vita? Ci sono due parametri. Sono relativamente nuovi. Possono essere attivati di default in diverse applicazioni. E possono rendere la vita molto più difficile se non sono attivati correttamente.

Ci sono due novità. Sono già presenti nei recenti kernel. Si tratta di sched_migration_cost in nanosecondi e sched_autogroup_enabled, che per default è impostato su uno.
E come rovinano la situazione? Cosa significa sched_migration_cost? Il gestore dei processi di Linux può migrare un processo da una CPU a un'altra. E per PostgreSQL, che esegue query, la migrazione su un'altra CPU non ha assolutamente senso. Dal punto di vista del sistema operativo, quando si passa da OpenOffice al terminale, potrebbe anche andare bene, ma per un database – è molto male. Pertanto, è sensato impostare migration_cost su un valore piuttosto alto, almeno alcune migliaia di nanosecondi.
Cosa significherà questo per il scheduler? Si considererà che durante questo tempo il processo sia ancora attivo. Cioè, se hai qualche transazione lunga che richiede tempo, il scheduler lo comprenderà. Fino a quando non scade questo timeout, non sarà necessario migrare questo processo altrove. Se il processo sta svolgendo un'attività, non verrà migrato; continuerà a funzionare sul CPU a cui è stato assegnato. Il risultato sarà eccellente.
Il secondo aspetto è l'autogruppo. È una buona idea per workload specifici che non riguardano i database moderni: raggruppare i processi in base al terminale virtuale da cui sono stati avviati. Questo è pratico per alcune attività. Nella pratica, PostgreSQL è un sistema multiprocessore con prefork, avviato da un unico terminale. Avrai lock writer, checkpoint e tutte le tue richieste client saranno raggruppate su un unico scheduler, su un'unica CPU. Attendono insieme che questa si liberi, per non ostacolarsi a vicenda e rimanere occupati più a lungo. Questa situazione non è affatto necessaria in caso di questo tipo di carico di lavoro, quindi è necessario disattivarla.

Il mio collega Alexey Lesovski ha condotto dei test con un semplice pgbench, aumentando di un ordine di grandezza il migration_cost e disattivando l'autogroup. La differenza su hardware scadente è stata quasi del 10%.C'è una discussione nella mailing list di Postgres, dove le persone riportano i risultati di come tali modifiche abbiano influito sulla velocità delle query. Hanno influito sul 50%.Ci sono molte storie simili.

E infine, riguardo alla politica di risparmio energetico. È positivo che ora Linux possa essere usato su un laptop, promettendo di utilizzare bene la batteria. Ma si scopre che la stessa cosa può valere anche per i server.
Inoltre, se affittate server da qualche provider, i "buoni" provider non si preoccupano di garantirvi prestazioni superiori. Il loro obiettivo è massimizzare l'utilizzo dell'hardware. Pertanto, possono attivare per impostazione predefinita la modalità risparmio energetico del portatile sul sistema operativo.
Se usate sul server con un database ad alta intensità questo sistema, la vostra scelta deve essere acpi_cpufreq + performance. Anche con ondemand avrete già dei problemi.
Intel_pstate – è un driver leggermente diverso. Attualmente, si preferisce questo, in quanto è più recente e funziona meglio.
Pertanto, il governor è solo performance. Ondemand, powersave e simili non sono per voi.
I risultati di explain analyze PostgreSQL possono variare di diversi ordini di grandezza se attivate powersave, poiché praticamente il CPU sarà schedulato in modo del tutto imprevedibile.
Queste impostazioni possono essere attivate di default. Controllate attentamente se sono state abilitate di default. Questo può essere davvero un grande problema.

Infine, vorrei ringraziare i ragazzi del nostro team DBA PosgreSQL-Consulting, in particolare Max Boguk e Alexey Lesovsky, che ogni giorno imparano a gestire queste questioni. Cerchiamo di fare del nostro meglio per i nostri clienti, affinché tutto funzioni. È come con le istruzioni di sicurezza aeree. Qui tutto è scritto col sangue. Ogni dado è stato scoperto durante un problema. Sono felice di condividerli con voi.
Domande:
Grazie! Se, ad esempio, un'azienda desidera risparmiare e ospitare su un unico server sia il database che la logica applicativa, o se segue la tendenza attuale verso architetture a microservizi in cui PostgreSQL viene eseguito in un container. Qual è il vantaggio? Sysctl influisce globalmente su tutto il kernel. Non ho sentito parlare di sysctl che venga virtualizzato in modo che funzioni separatamente nei container. Esistono solo cgroup e lì il controllo è limitato. Come si può convivere con questo? Oppure, se desiderate performance, allora eseguite PostgreSQL su un server fisico dedicato e ottimizzatelo?
Abbiamo risposto alla vostra domanda in circa tre modi. Se non si tratta di un server fisico che può essere ottimizzato, state tranquilli, tutto funzionerà bene anche senza queste impostazioni. Se la vostra carico di lavoro è tale da richiedere queste configurazioni, arriverete a un server fisico prima di dovervi preoccupare di queste impostazioni.
Qual è il problema? Se si tratta di una macchina virtuale, probabilmente avrai molti problemi, come ad esempio un'latency del disco piuttosto incoerente su molte macchine virtuali. Anche se la banda passante dei dischi è buona, una transazione di input/output che ha avuto problemi, che non incide molto sulla banda media, ma si verifica durante un checkpoint o durante la scrittura nel WAL, causerà molti danni al database. E lo noterai prima di affrontare questi problemi.
Se hai NGINX sullo stesso server, avrai lo stesso problema. Si contenderanno la memoria condivisa. E non arriverai ai problemi descritti qui.
D'altra parte, alcuni di questi parametri saranno comunque rilevanti per te. Ad esempio, impostare dirty_ratio con sysctl per non avere un valore eccessivo – in ogni caso questo aiuterà. In ogni caso, avrai interazioni con il disco. E seguiranno uno schema errato. Questi sono i parametri default che ho mostrato. In ogni caso, è meglio modificarli.
Ci possono essere problemi con NUMA. VmWare, ad esempio, funziona bene con NUMA con impostazioni esattamente opposte. Qui si deve scegliere: server fisico o non fisico.
Ho una domanda riguardo ad Amazon AWS. Hanno immagini preimpostate. Una di queste si chiama Amazon RDS. Ci sono impostazioni personalizzate per il loro sistema operativo?
Ci sono impostazioni, ma sono impostazioni diverse. Qui configuriamo il sistema operativo dal punto di vista di come il database utilizzerà il tutto. Lì ci sono parametri che determinano la direzione in cui dobbiamo andare, un tipo di shaping. Cioè, abbiamo bisogno di queste risorse, e ora le consumeremo. Dopo di che, Amazon RDS integra queste risorse e lì la performance diminuisce. Ci sono storie su come le persone iniziano a lavorare su questo. A volte anche con successo. Ma ciò non riguarda le impostazioni del sistema operativo. È come fare hacking sul cloud. È un'altra storia.
Perché le Transparent huge pages non producono effetti rispetto a Huge TLB?
Non lo danno. Si può spiegare in molti modi, ma di fatto non lo danno. Qual è la storia di PostgreSQL? All'avvio, riserva un grande pezzo di memoria condivisa. Se sono trasparenti o meno è completamente irrilevante. Il fatto che vengano allocati all'avvio spiega tutto. E se c'è molta memoria e bisogna ristrutturare il segmento di memoria condivisa, allora le Transparent huge pages diventano rilevanti. In PostgreSQL, questa memoria è semplicemente allocata in un grande blocco all'avvio e basta, e poi non succede nulla di particolare. Si può usare, certo, ma c'è il rischio di ottenere una corruzione della memoria condivisa quando viene riallocato qualcosa. PostgreSQL non sa niente di questo.
Fonte: habr.com
