Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

Introduzione

Non molto tempo fa mi è stato chiesto di sviluppare un cluster ad alta disponibilità per PostgreSQL, operante in diversi data center collegati tramite fibra ottica all'interno di una stessa città e in grado di sostenere il guasto (ad esempio, l'interruzione di corrente) di un data center. Come software responsabile della resilienza, ho scelto Pacemaker, poiché è la soluzione ufficiale di RedHat per la creazione di cluster ad alta disponibilità. È vantaggioso perché RedHat offre supporto per questa tecnologia e inoltre è una soluzione versatile (modulare). Con essa è possibile garantire l'alta disponibilità non solo per PostgreSQL, ma anche per altri servizi, sia utilizzando moduli standard che creandone di specifici per esigenze particolari.

A questo proposito sorge una domanda ragionevole: quanto è davvero affidabile un cluster resiliente? Per indagare, ho creato un banco di prova che simula vari guasti nei nodi del cluster, attende il ripristino della funzionalità, recupera il nodo guasto e continua a testare in ciclo. Inizialmente, questo progetto si chiamava hapgsql, ma col tempo mi sono stancato di un nome con solo una vocale. Pertanto, le basi di dati resilienti (e gli IP float associati) li ho chiamati krogan (un personaggio di un videogioco, che ha tutti gli organi vitali duplicati), e i nodi, i cluster e il progetto stesso — tuchanka (il pianeta abitato dai krogan).

Attualmente, la direzione ha autorizzato l'apertura del progetto alla comunità open source sotto la licenza MIT. Il README sarà tradotto in inglese a breve (poiché ci si aspetta che i principali utilizzatori siano sviluppatori di Pacemaker e PostgreSQL), e la vecchia versione russa del README ho deciso di presentarla (parzialmente) in forma di questo articolo.

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

I cluster vengono distribuiti su macchine virtuali VirtualBox. Saranno distribuite 12 macchine virtuali (per un totale di 36GiB), che formeranno 4 cluster ridondanti (varie opzioni). I primi due cluster consistono in due server PostgreSQL, situati in diversi data center, e un server condiviso testimone c dispositivo di quorum (collocato su una macchina virtuale economica in un terzo data center), che risolve l'incertezza 50%/50%, esprimendo il suo voto per una delle parti. Il terzo cluster si trova in tre data center: un master, due schiavi, senza dispositivo di quorum. Il quarto cluster è composto da quattro server PostgreSQL, due per data center: uno master, le altre repliche, e utilizza anche testimone c dispositivo di quorum. Il quarto resiste al guasto di due server o di un data center. Questa soluzione può, se necessario, essere scalata a un numero maggiore di repliche.

Servizio di sincronizzazione dell'ora ntpd è stato anche riconfigurato per la ridondanza, ma utilizza il metodo di ntpd (orphan mode). Il server centrale testimone funge da server NTP centrale, distribuendo il proprio tempo a tutti i cluster, sincronizzando così tutti i server tra loro. Se testimone si guasta o viene isolato, uno dei server del cluster inizierà a distribuire il proprio tempo (all'interno del cluster). Un cache ausiliario proxy HTTP è anch'esso attivo su testimone, tramite il quale le altre macchine virtuali hanno accesso ai repository Yum. In realtà, servizi come l'ora esatta e il proxy saranno sicuramente ospitati su server dedicati, mentre nel banco sono ospitati su testimone solo per risparmiare sul numero di macchine virtuali e spazio.

Versioni

v0. Funziona con CentOS 7 e PostgreSQL 11 su VirtualBox 6.1.

Struttura dei cluster

Tutti i cluster sono progettati per essere ospitati in diversi data center, uniti in una rete piatta e devono resistere al fallimento o all'isolamento di rete di un data center. Pertanto non è possibile utilizzare per la protezione da split-brain la tecnologia standard Pacemaker, che si chiama STONITH (Shoot The Other Node In The Head) o fencing. La sua essenza: se i nodi nel cluster iniziano a sospettare che ci sia qualcosa di strano con un nodo, che non risponde o si comporta in modo anomalo, lo scollegano forzatamente tramite dispositivi "esterni", come la scheda di gestione IPMI o l'UPS. Tuttavia, questo funzionerà solo nei casi in cui, in caso di guasto singolo del server, IPMI o UPS continuino a funzionare. Qui è prevista una protezione da un guasto molto più catastrofico, quando fallisce (ad esempio, si interrompe l'alimentazione) l'intero data center. E in caso di tale guasto, tutto stonith-i dispositivi (IPMI, UPS, ecc.) non funzioneranno nemmeno.

Invece, il sistema si basa sull'idea del quorum. Tutti i nodi hanno diritto di voto e possono lavorare solo quelli che vedono più della metà di tutti i nodi. Questa quantità "metà+1" è chiamata quorum. Se il quorum non viene raggiunto, il nodo decide che si trova in isolamento di rete e deve disattivare le proprie risorse, cioè è una sorta di protezione da split-brain. Se il software che gestisce questo comportamento non funziona, si deve attivare un watchdog, ad esempio basato su IPMI.

Se il numero di nodi è pari (cluster in due data center), può verificarsi quella che viene chiamata incertezza 50%/50% (cinquanta-cinquanta), quando l'isolamento di rete divide il cluster esattamente a metà. Pertanto, per un numero pari di nodi, si aggiunge dispositivo di quorum — un demone poco esigente che può essere avviato sulla virtual machine più economica nel terzo data center. Esso dà il suo voto a uno dei segmenti (che vede), risolvendo così l'incertezza 50%/50%. Il server su cui verrà eseguito il quorum device l'ho chiamato testimone (terminologia di repmgr, mi è piaciuta).

Le risorse possono spostarsi da un posto all'altro, ad esempio, da server guasti a server funzionanti, o su comando degli amministratori di sistema. Per informare i clienti su dove si trovano le risorse di cui hanno bisogno (a quale punto connettersi?), vengono utilizzati IP galleggianti (float IP). Questi IP possono essere spostati da Pacemaker tra i nodi (tutto si trova in una rete piatta). Ognuno di essi rappresenta una risorsa (servizio) e sarà posizionato dove è necessario connettersi per accedere a questo servizio (nel nostro caso, al DB).

Tuchanka1 (schema di compressione)

Struttura

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

L'idea era quella di avere molti piccoli database con un basso carico, per i quali non è conveniente mantenere un server slave dedicato in modalità hot standby per transazioni in sola lettura (non c'è bisogno di uno spreco di risorse del genere).

In ogni data center c'è un server. Ogni server ha due istanze di PostgreSQL (nella terminologia di PostgreSQL si chiamano claster, ma per evitare confusione le chiamerò istanze, analogamente ad altre DB, e chiamerò cluster solo i cluster Pacemaker). Un'istanza funziona in modalità master e solo essa fornisce servizi (solo su di essa è presente un IP fluttuante). L'altra istanza funziona come slave per il secondo data center e fornirà servizi solo se il suo master dovesse andare offline. Poiché la maggior parte del tempo fornirà servizi (eseguirà query) solo un'istanza su due (il master), tutte le risorse del server vengono ottimizzate per il master (viene allocata memoria per il cache shared_buffers, ecc.), ma in modo tale da garantire risorse anche per la seconda istanza (anche se con prestazioni non ottimali tramite la cache del filesystem) nel caso in cui uno dei data center dovesse fallire. Lo slave non fornisce servizi (non esegue query di sola lettura) durante il normale funzionamento del cluster, per evitare di competere per le risorse con il master sulla stessa macchina.

Nel caso di due nodi, l'affidabilità è possibile solo con la replicazione asincrona, in quanto con la replicazione sincronizzata il guasto dello slave porterà alla fermata del master.

Guasto witness

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

Guasto witness (dispositivo di quorum) lo considero solo per il cluster Tuchanka1, per tutti gli altri sarà la stessa storia. In caso di guasto del witness nella struttura del cluster, nulla cambierà, tutto continuerà a funzionare come prima. Tuttavia, il quorum diventerà 2 su 3, e quindi qualsiasi successivo guasto diventerà fatale per il cluster. Sarà comunque necessario ripararlo rapidamente.

Guasto Tuchanka1

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

Guasto di uno dei data center per Tuchanka1. In questo caso testimone vota per il secondo nodo nel secondo data center. Qui l'ex slave si trasforma in master, quindi entrambi i master funzionano su un server e entrambi puntano al loro float IP.

Tuchanka2 (classico)

Struttura

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

Schema classico composto da due nodi. Uno ospita il master, l'altro lo slave. Entrambi possono gestire le richieste (lo slave è solo read only), quindi entrambi puntano al float IP: krogan2 — per il master, krogan2s1 — per lo slave. L'affidabilità sarà sia per il master che per lo slave.

Nel caso di due nodi, la tolleranza ai guasti è possibile solo con la replicazione asincrona, poiché con la replicazione sincrona un guasto del server secondario porterà all'arresto del master.

Guasto Tuchanka2

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

In caso di guasto di uno dei data center testimone voterebbe per il secondo. Nel data center attivo verrà avviato il master, e entrambi gli IP float: quello master e quello secondario, punteranno su di esso. Naturalmente, l'istanza deve essere configurata in modo tale da avere risorse sufficienti (limiti di connessione, ecc.) per accettare simultaneamente tutte le connessioni e le richieste dagli IP float master e secondario. Cioè, in condizioni normali, deve avere un margine sufficiente sui limiti.

Tuchanka4 (molti secondari)

Struttura

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

Già un'altra estremità. Ci sono database che ricevono molte richieste in sola lettura (caso tipico di un sito ad alto carico). Tuchanka4 è la situazione in cui possono esserci tre o più secondari per gestire tali richieste, ma comunque non troppi. Con un numero eccessivo di secondari, sarà necessaria l'ideazione di un sistema gerarchico di replicazione. Nel caso minimo (nell'immagine) ci sono due server in ciascuno dei due data center, ognuno con un'istanza di PostgreSQL.

Un'altra caratteristica di questo schema è che qui è possibile organizzare una replica sincrona. È configurata per replicare, se possibile, in un altro data center, e non su una replica nello stesso data center del master. Il master e ogni slave sono indicati da un IP float. Idealmente, tra gli slave si dovrebbe effettuare il bilanciamento delle richieste tramite qualche sql proxy, per esempio, sul lato client. A diversi tipi di client potrebbe servire un tipo diverso sql proxy, e solo gli sviluppatori dei client sanno quale sia necessario per ognuno. Questa funzionalità può essere implementata sia come demone esterno, sia come libreria client (connection pool), ecc. Tutto ciò esula dal tema del cluster DB ad alta disponibilità (l'alta disponibilità SQL proxy può essere implementata indipendentemente, insieme all'alta disponibilità del client).

Guasto Tuchanka4

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

In caso di malfunzionamento di un data center (ovvero di due server), il witness vota per il secondo. Di conseguenza, in quest'ultimo data center operano due server: su uno si trova il master, al quale corrisponde un float IP master (per ricevere richieste read-write); mentre sull'altro server opera uno slave con replica sincrona, al quale corrisponde uno dei float IP slave (per richieste read only).

La prima cosa da notare è che il float IP slave attivo non sarà tutti, ma solo uno. E per funzionare correttamente, è necessario che sql proxy reindirizzi tutte le richieste all'unico float IP rimanente; e se sql proxy no, è possibile elencare tutti i float IP degli slave separati da una virgola nell'URL per la connessione. In tal caso, con libpq la connessione avverrà al primo IP operativo, come previsto nel sistema di test automatici. Potrebbe non funzionare allo stesso modo in altre librerie, ad esempio JDBC, e potrebbe essere necessario sql proxy. Questo perché per i float IP degli slave è vietato attivarsi contemporaneamente su un server, affinché siano distribuiti uniformemente tra i server slave, se ce ne sono diversi attivi.

In secondo luogo: anche in caso di guasto del data center, la replica sincrona sarà mantenuta. E anche se si verifica un guasto secondario, ovvero uno dei due server nel data center rimanente si guasta, il cluster smetterà di fornire servizi, ma manterrà comunque informazioni su tutte le transazioni impegnate per le quali ha fornito conferma di commit (non ci sarà perdita di informazioni in caso di guasto secondario).

Tuchanka3 (3 data center)

Struttura

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

Questo è un cluster per la situazione in cui ci sono tre data center completamente operativi, ciascuno con un server di database completamente funzionante. In questo caso dispositivo di quorum non è necessario. In un data center opera il master, mentre negli altri due ci sono i server slave. La replica è sincrona, tipo ANY (slave1, slave2), il che significa che il cliente riceverà conferma del commit quando uno degli slave risponderà per primo di aver accettato il commit. Le risorse indicano un IP float per il master e due per gli slave. A differenza di Tuchanka4, tutti e tre gli IP float sono a prova di guasto. Per bilanciare le richieste SQL in sola lettura è possibile utilizzare sql proxy (con affidabilità separata), oppure si può assegnare un IP float a un gruppo di clienti e un altro a un secondo gruppo.

Guasto Tuchanka3

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

Se uno dei data center dovesse crollare, ne rimarrebbero due. In uno è attivato il master e l'IP flottante dal master, nell'altro — lo slave e entrambi gli IP flottanti slave (l'istanza deve avere una riserva doppia di risorse per accettare tutte le connessioni da entrambi gli IP flottanti slave). Tra master e slave c'è una replica sincrona. Inoltre, il cluster manterrà le informazioni sulle transazioni impegnate e confermate (non ci sarà perdita di informazioni) in caso di distruzione di due data center (se distrutti non contemporaneamente).

Ho deciso di non includere una descrizione dettagliata della struttura dei file e del deployment. Chi desidera sperimentare può leggere tutto nel README. Fornisco solo la descrizione del test automatico.

Sistema di test automatico

Per verificare la tolleranza ai guasti dei cluster simulando vari difetti, è stato creato un sistema di test automatico. Viene avviato tramite script test/failure. Lo script può accettare come parametri i numeri dei cluster che si desidera testare. Ad esempio, il comando è:

test/failure 2 3

verrà testato solo il secondo e il terzo cluster. Se i parametri non sono specificati, verranno testati tutti i cluster. Tutti i cluster vengono testati in parallelo e il risultato viene visualizzato nel pannello tmux. Tmux utilizza un server tmux dedicato, quindi lo script può essere eseguito all'interno del tmux predefinito, creando un tmux annidato. Consiglio di utilizzare il terminale in una finestra grande e con un carattere piccolo. Prima dell'inizio dei test, tutte le macchine virtuali vengono ripristinate a uno snapshot al momento del completamento dello script. setup.

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

Il terminale è suddiviso in colonne in base al numero di cluster testati, di default (nello screenshot) sono quattro. Contenuto delle colonne che descriverò usando l'esempio Tuchanka2. I pannelli nello screenshot sono numerati:

  1. Qui viene visualizzata la statistica dei test. Colonne:
    • failure — il nome del test (funzioni nello script) che simula un guasto.
    • reaction — la media aritmetica del tempo in secondi, necessario perché il cluster ripristini la sua operatività. Viene misurata dal momento in cui inizia l'esecuzione di uno script che emula un guasto fino al momento in cui il cluster ripristina la sua operatività e può continuare a fornire servizi. Se il tempo è molto breve, ad esempio sei secondi (come avviene nei cluster con più schiavi (Tuchanka3 e Tuchanka4)), significa che il guasto è avvenuto in uno schiavo asincrono e non ha influenzato l'operatività; non ci sono stati cambiamenti di stato nel cluster.
    • deviazione — mostra la dispersione (accuratezza) del valore reaction utilizzando il metodo della «deviazione standard».
    • conteggio — quante volte è stato eseguito questo test.
  2. Il registro di sintesi consente di valutare cosa stia facendo attualmente il cluster. Viene riportato il numero dell'iterazione (del test), il timestamp e il nome dell'operazione. Un tempo di esecuzione troppo lungo (> 5 minuti) indica un problema.
  3. cuore (heart) — il tempo attuale. Per una valutazione visiva dell'operatività del master il tempo attuale viene continuamente registrato nella sua tabella utilizzando l'IP float del master. In caso di successo, il risultato viene visualizzato in questo pannello.
  4. battito (pulse) — «tempo corrente», precedentemente registrato dallo script cuore in master, ora letto da slave tramite il suo IP flottante. Permette di valutare visivamente il funzionamento dello slave e della replicazione. In Tuchanka1 non ci sono slave con IP flottante (nessuno slave offre servizi), ma ci sono due istanze (DB), quindi qui verrà mostrato non battito, e cuore la seconda istanza.
  5. Monitoraggio dello stato del cluster tramite l'utility pcs mon. Mostra la struttura, la distribuzione delle risorse tra i nodi e altre informazioni utili.
  6. Qui viene visualizzato il monitoraggio di sistema da ogni virtual machine del cluster. Ci possono essere più di questi pannelli — quanti sono i virtual machines del cluster. Due grafici CPU Load (nelle virtual machines ci sono due processori), nome della virtual machine, System Load (chiamato Load Average, perché è mediato su 5, 10 e 15 minuti), dati sui processi e distribuzione della memoria.
  7. Tracciamento dello script che esegue i test. In caso di malfunzionamento — interruzione improvvisa del lavoro o ciclo di attesa infinito — qui sarà possibile vedere la causa di tale comportamento.

Il test viene eseguito in due fasi. Inizialmente, lo script attraversa tutte le variazioni di test, selezionando casualmente la macchina virtuale a cui applicare il test. Successivamente, viene eseguito un ciclo infinito di test, in cui le macchine virtuali e i malfunzionamenti vengono scelti casualmente ogni volta. Un'improvvisa chiusura dello script di test (nella barra inferiore) o un ciclo infinito in attesa di qualcosa (> 5 minuti di tempo per l'esecuzione di un'operazione, visibile nello stack trace) indica che uno dei test su questo cluster è fallito.

Ogni test consiste nelle seguenti operazioni:

  1. Avvio di una funzione che simula un malfunzionamento.
  2. Pronto? — attesa del ripristino delle funzionalità del cluster (quando tutti i servizi sono disponibili).
  3. Viene mostrato il tempo di attesa per il ripristino del cluster (reaction).
  4. Fix — il cluster 'viene riparato'. Dopodiché, dovrebbe tornare a uno stato completamente operativo e pronto per il prossimo malfunzionamento.

Ecco un elenco dei test con una descrizione di cosa fanno:

  • ForkBomb: genera 'Out of memory' tramite una fork bomb.
  • OutOfSpace: il disco rigido è pieno. Ma il test è più simbolico, dato il carico trascurabile che si crea durante il test; in caso di sovraccarico del disco rigido, PostgreSQL solitamente non va in errore.
  • Postgres-KILL: termina PostgreSQL con il comando killall -KILL postgres.
  • Postgres-STOP: sospende PostgreSQL con il comando killall -STOP postgres.
  • PowerOff: «spegne» la VM con il comando VBoxManage controlvm "virtual machine" poweroff.
  • Reset: riavvia la VM con il comando VBoxManage controlvm "virtual machine" reset.
  • SBD-STOP: sospende il demone SBD con il comando killall -STOP sbd.
  • ShutDown: invia alla VM il comando via SSH systemctl poweroff, il sistema termina correttamente.
  • UnLink: isolamento di rete, comando VBoxManage controlvm "virtual machine" setlinkstate1 off.

Fine del test oppure utilizzando il comando standard tmux "kill-window" Ctrl-b &, oppure il comando "detach-client" Ctrl-b d: in questo caso il test si conclude, tmux si chiude e le VM vengono spente.

Problemi riscontrati durante il test

  • Attualmente il demone watchdog sbd gestisce l'arresto dei demoni osservati, ma non il loro blocco. E, di conseguenza, le anomalie che portano al blocco vengono gestite in modo errato, determinando Corosync e Pacemaker, ma senza bloccare sbd. Per la verifica Corosync è già presente PR#83 (su GitHub, sbd), accettato nel ramo master. Hanno promesso (in PR#83) che ci sarà qualcosa di simile per Pacemaker, spero che a RedHat 8 lo faranno. Tuttavia, tali "malfunzionamenti" sono teorici e possono essere facilmente simulati artificialmente, ad esempio, killall -STOP corosync, ma non si verificano mai nella vita reale.

  • A Pacemaker nella versione per CentOS 7 è impostato in modo errato sync_timeout a dispositivo di quorum, di conseguenza in caso di guasto di un nodo, con una certa probabilità anche il secondo nodo, su cui avrebbe dovuto spostarsi il master, si riavviava. È stato risolto aumentando sync_timeout a dispositivo di quorum durante il deployment (nello script setup/setup1). Questa correzione non è stata accettata dagli sviluppatori Pacemaker, invece hanno promesso di riprogettare l'infrastruttura in modo tale (in un futuro indefinito) che questo timeout venga calcolato automaticamente.

  • Se durante la configurazione del database viene indicato che in LC_MESSAGES (messaggi di testo) può essere utilizzato Unicode, ad esempio, ru_RU.UTF-8, allora all'avvio postgres in un ambiente dove il locale non è UTF-8, ad esempio, in un ambiente vuoto (qui pacemaker+pgsqlms(paf) avvia postgres), allora nel log invece dei caratteri UTF-8 ci saranno punti interrogativi. Gli sviluppatori di PostgreSQL non hanno ancora raggiunto un accordo su cosa fare in questo caso. Si può aggirare il problema impostando LC_MESSAGES=en_US.UTF-8 durante la configurazione (creazione) di un'istanza DB.

  • Se è impostato wal_receiver_timeout (di default 60s), durante il test PostgreSQL-STOP sul master nei cluster tuchanka3 e tuchanka4 non si verifica la riconnessione della replica al nuovo master.La replica è sincrona, quindi si interrompe non solo il lavoro, ma anche il nuovo master. Si risolve impostando wal_receiver_timeout=0 durante la configurazione di PostgreSQL.

  • Ho osservato raramente il congelamento della replica in PostgreSQL durante il test ForkBomb (overflow di memoria). Dopo ForkBomb, a volte gli schiavi possono non riconnettersi al nuovo master.Ho riscontrato questo solo nei cluster tuchanka3 e tuchanka4, dove, a causa della replica sincrona, il master si bloccava. Il problema si risolveva da solo dopo un certo periodo (circa due ore). È necessaria un'ulteriore indagine per risolverlo. Per sintomi sembra un bug precedente causato da un'altra ragione, ma con le stesse conseguenze.

L'immagine del krogan è tratta da Deviant Art con il permesso dell'autore:

Modellazione di cluster resistenti ai guasti basati su PostgreSQL e Pacemaker.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS 🔥 Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS | ProHoster