Il cluster Galera (Percona XtraDB Cluster) in uso ai LNF è composto da 3 nodi in configurazione multi-master, connessi verso l'utenza attraverso un load-balancer come rappresentato nel diagramma seguente:
I nodi sono cosi organizzati:
I test eseguiti mirano a verificare (in maniera non formale) il corretto funzionamento del cluster nel rispetto delle caratteristiche attese:
In maggior dettaglio, queste caratteristiche sono garantite dalla replicazione dei dati sui vari nodi (disaster recovery), che interagiscono coordinandosi nella fornitura del servizio al fine di ovviare a eventuali malfunzionamneti delle diverse componenti HW/SW del cluster (fault tolerance).
I test riguardano tre casistiche distinte:
Queste tipologie di test non hanno lo scopo di coprire o indentificare tutte le situazioni che portano ad un malfunzionamento, ma piuttosto ad individuare i problemi più comuni nella gestione di un tale cluster e sopratutto a definire gli interventi necessari in questi casi.
Vengono di seguito riportati le definizioni dei test e le osservazioni a riguardo.
Il partizionamento della rete è stato simulato attraverso la definizione di alcune regole per iptables: il guasto su un segmento di connessione è quindi simulato introducendo quindi due regole distinte:
iptables -A INPUT -s <other_host_ip> -j DROP iptables -A OUTPUT -d <other_host_ip> -j DROP
quindi il nodo con ip <other_host_ip>
apparirà completamente isolato rispetto all'host sul quale si imposta la regola.
Un cluster Galera viene considerato il concetto di Primary Component, ovvero l'insieme di nodi che formano una partizione in numero sufficiente a raggiungere la maggioranza dei nodi totali.
In questo caso di studio viene simulato il fault di un solo segmento di rete, come mostrato dallo schema:
In questo scenario, i nodi riescono ancora a condividere lo stato del cluster, e il funzionamento non viene inificiato.
In questo caso viene simulato il partizionamento della rete interrompendo la comunicazione tra due segmenti (1):
A questo punto un nodo del cluster (F nello schema) non riuscendo più a raggiungere gli altri due nodi, si ritrova isolato e interrompe il funzionamento (2). Ad ogni interrogazione risponderà con un messaggio del genere:
ERROR 1047 (08S01) at line 1: WSREP has not yet prepared node for application use
Lo stato del nodo rispetto al cluster può essere verificato interrogando la variabile wsrep_ready
:
SHOW STATUS WHERE Variable_name='wsrep_ready'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | wsrep_ready | OFF | +---------------+-------+
Possiamo inoltre verificare la cardinalità del cluster con:
SHOW STATUS WHERE Variable_name='wsrep_cluster_size';
Se la query viene effettuata sul nodo isolato (F nel nostro caso) la risposta sarà:
+--------------------+-------+ | Variable_name | Value | +--------------------+-------+ | wsrep_cluster_size | 1 | +--------------------+-------+
Mentre se l'interrogazione avviene su uno degli altri nodi si avrà:
+--------------------+-------+ | Variable_name | Value | +--------------------+-------+ | wsrep_cluster_size | 2 | +--------------------+-------+
In questa situazione, i nodi che continuano a comunicare tra loro costituiscono il Primary Component.
A questo punto, se si procede al recovery, il nodo isolato potrebbe contattare nuovamente i nodi, e tornare a far parte del cluster. Immaginando di rispristinare un segmento di rete alla volta, diciamo il segmento F-G, il nodo precedentemente isolato tenta di sincronizzarsi con fli altri nodi, quindi individua un nodo all'interno del Primary Component al quale richiedere una copia aggiornata dei dati (chiamato donor). Se la scelta dovesse ricadere sul nodo non direttamente raggiungibile a causa del fault di rete non ancora risolto (nel caso L), il nodo non raggiungerebbe il nodo donor designato (3). In questa situazione, il nodo isolato non può effettuare il sync e dopo un certo numero di tentativi spegne il servizio (4).
Per ovviare al problema, è possibile forzare il donor utilizzato per il sync impostando una voce nel file di configurazione del servizio, ora spento sul server isolato:
wsrep_sst_donor='<node_name>'
Dove <node_name>
è il nome del nodo donor come specificato sul file di configurazione del servizio mysqld sul nodo donor, ad esempio:
... wsrep_node_name='<node_name>' ...
Prima di riavviare il servizio sul nodo precedentemente isolato, è necessario assicurarsi che tutti i nodi presenti nella la lista alla voce wsrep_cluster_address
nel file di configurazione del servizio siano effettivamente raggiungibili. Ad esempio, se abbiamo:
... wsrep_cluster_address="gcomm://<node_G_ip>,<node_L_ip>,<node_F_ip>" ...
e supponendo che il nodo isolato abbia ip <node_F_ip>
, dobbiamo assicurarci che gli indirizzi <node_G_ip>
e <node_L_ip>
siano raggungibili (nel caso in esempio, questo presuppone che entrambi i fault sulla rete siano stati risolti). In caso contrario, il servizio non potrà partire, e l'avvio fallirà. Per ovviare al problema, supponendo che il collegamento ripristinato sia quello in figura al punto (3) che congiunge i nodi G e F, possiamo impostare:
... wsrep_cluster_address="gcomm://<node_G_ip>,<node_F_ip>" wsrep_node_name='<node_G_name>' ...
E avviare il server. Dopo aver constatato il corretto riavvio, e dopo aver ripristinato per intero le connessioni di rete, possiamo ripristinare le voci sul file di configurazione ai valori originari, e modificare la variabile (dinamica) per rispecchiare la configurazione del cluster con la query:
SET GLOBAL wsrep_cluster_address='gcomm://<node_G_ip>,<node_L_ip>,<node_F_ip>';
Durante i test effettuati non sono stati riscontrati interruzioni del servizio o malfunzionamenti anche nel caso in cui i nodi che vengono spenti siano due.
Il cluster in questo caso, diviene consapevole della riduzione della cardinalità del cluster (e del Primary Component) e modifica il metodo di calcolo del quorum per consentire il funzionamento, in maniera del tutto automatica.
Nel test precedente i nodi "uscenti" dal cluster si preoccupano di informare gli altri nodi del proprio cambiamento di stato prima di spegnersi. Se lo spegnimento avviene in maniera ungraceful (in parole povere "staccando la spina" del nodo) questo scambio di informazioni non può avvenire, con tutte le conseguenze del caso.
Questo fa capire come questo tipo di situazioni causano i problemi pià difficili da gestire, e spesso richiedono manutenzione supervised sul cluster. Lo spegninmento improvviso è stato simulato con la funzione "Power Off" fornita da OVirt che spegne nella maniera più veloce (e brusca) possibile una macchina virtuale.
Spegnendo un solo nodo, il cluster viene mantenuto in vita dai nodi restanti che si accorgono velocemente della mancanza del nodo spento; non è necessario nessun intervento manuale.
Quando un ulteriore nodo viene spento, il nodo superstite non riceve nessuna informazione sullo spegnimento imminente, e non ha la possibilità di rimodulare il calcolo del quorum necessario al funzionamento del cluster. Quindi è costretto a interrompere la gestione delle richieste (come schematizzato in figura).
Infatti, se immettiamo la query:
SHOW STATUS WHERE Variable_name='wsrep_ready' OR Variable_name='wsrep_local_state_comment' OR Variable_name='wsrep_cluster_status' OR Variable_name='wsrep_cluster_size';
Possiamo analizzare la risposta ricevuta:
+---------------------------+--------------+ | Variable_name | Value | +---------------------------+--------------+ | wsrep_local_state_comment | Initialized | | wsrep_cluster_size | 1 | | wsrep_cluster_status | Non-Primary | | wsrep_ready | OFF | +---------------------------+--------------+
E quindi constatare che il nodo non è operativo e inoltre non far parte del Primary Component (dato che non esiste una partizione di nodi del cluster funzionanti, connessi e in maggioranza). Se un nodo precedentemente spento torna in funzione, il cluster torna ad essere operativo in maniera canonica (ovviamente anche se tornano operativi più nodi). Il nodo superstite può comunque riprendere le attività in autonomia, con la digitazione della query:
SET GLOBAL wsrep_provider_options='pc.bootstrap=true';
A questo punto il nodo continua ad operare in attesa che gli altri nodi vengano rispristinati, garantendo il servizio ma ovviamente ne fault tolerance ne disaster recovery, non essendoci replicazione.
Quando l'interruzione del servizio riguarda l'intero cluster, il problema si complica, poichè possono presentarsi casi di split brain e inconsistenza dei dati. I nodi del cluster devono quindi essere riavviati attivando per primo il nodo con la sequenza di modifiche più recenti sui datafile del DB. Possiamo individuare quindi il numero di sequenza dei nodi lanciando:
# mysqld_safe --wsrep-recover 151105 15:41:34 mysqld_safe Logging to '/var/lib/mysql/<hostname>.err'. 151105 15:41:34 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql 151105 15:41:34 mysqld_safe WSREP: Running position recovery with --log_error='/var/lib/mysql/wsrep_recovery.PATt6w' --pid-file='/var/lib/mysql/<hostname>-recover.pid' 151105 15:41:36 mysqld_safe WSREP: Recovered position 35114f7b-7320-11e5-9e1e-7f73435b73aa:259056 151105 15:41:39 mysqld_safe mysqld from pid file /var/lib/mysql/<hostname>.pid ended
La stringa alla penultima voce indica, a fine riga, il numero di sequenza (nel nostro caso 259056). Il nodo che risulta avere il numero di sequenza più alto deve essere riavviato per primo. Per riavviare il server con numero di sequenza superiore digitare:
# systemctl start mysql@bootstrap.service
In seguito poi è possibile riavviare i restanti nodi, che entreranno a far parte del cluster in maniera automatica.
I problemi evidenziati ai punti precedenti si presentamo principalmente quando un'operazione di sync (link alle operazioni di sst) ha luogo all'interno del cluster. Per monitorare lo stato dei nodi rispetto alla sincronizzazione all'interno dei cluster, possiamo utilizzare sui vari nodi la query:
SHOW STATUS LIKE 'wsrep_local_state_comment';
I valori che la variable può assumere sono:
Si noti che durante le fasi di sincronizzazione i due nodi coinvolti non risultano operativi per tutta la durata del trasferimento, quindi le comunicazioni verso un nodo che si trova in stato "Donor/Desynced" o "Joining: receiving state transfer" risulteranno sospese;