MySQL GTID Replication

La funzionalita' di replica dati di MySQL e' semplice da configurare, richiede poca manutenzione, e' molto flessibile e non aggiunge carico al database Master: tutto questo ne spiega la forte diffusione. La gestione del failover tuttavia non e' semplicissima e va eseguita con una certa attenzione... Dalla versione 5.6 sono stati introdotti i Global Transaction Identifier (GTID) che semplificano notevolmente il failover ed in generale la gestione della replica MySQL. L'aggancio di uno Slave avviene infatti con il semplice comando: change master to master_auto_position=1.

Questa pagina riporta gli elementi principali sulla configurazione e gestione della replica MySQL con GTID.

Nel seguito sono riportate alcune informazioni di interesse organizzate in paragrafi specifici: Introduzione, Configurazione, Architettura, Amministrazione, ...

Un'introduzione generale sulla replica in MySQL si trova su questo documento.

Introduzione

Storicamente la replicazione su MySQL e' basata sugli statement, asincrona e l'identificazione degli statement e' file position based.
Il Master si occupa di registrare su file (bin-log file) tutti gli statement che vengono eseguiti sulla base dati e che operano una qualche modifica ai dati (DML e DDL). Le istruzioni registrate sono identificate mediante la loro posizione nei file bin-log.
Lo Slave si collega con un thread al Master, raccoglie il contenuto dei bin-log, lo trasferisce in locale e quindi si occupa di applicarlo alla base dati.

Architettura MySQL Replication

Ogni versione di MySQL ha introdotto nuove funzionalita' e dalla versione 5.6.5 sono stati introdotti i Global Transaction Identifier (GTID).
Un GTID e' composto da source_id:transaction_id dove il source_id e' l'identificativo del server che ha originato la transazione mentre il transaction_id e' il numero progressivo della transazione.
Utilizzando la replica basata su GTID non e' piu' necessario indicare file e posizione delle istruzioni da cui riallienare gli slave poiche' questo avviene in automatico. Questo semplifica notevolmente le operazioni di failover (nel caso di crash del master), di switchover (nel caso di modifica della topologia di replica) e di sincronizzazione degli slave... In pratica i principali vantaggi della replica GTID sono due:

Questo documento fa riferimento alla versione MySQL 5.7.6 o successiva poiche' da tale versione sono state consolidate tutte le funzionalita' introdotte in precedenza sul GTID.

Configurazione GTID

La configurazione della replica con GTID e' simile a quella della replica file-based. La documentazione completa e' presente nel sito ufficiale, quindi nel seguito riportiamo un semplice esempio di configurazione... ma che copre tutti i punti fondamentali per l'avvio di una nuova replica direttamente con GTID!

Attivita' sul Master
 
Attivita' sullo Slave
 
Note
 
[mysqld]
server-id=10
log-bin=mysql-bin
enforce-gtid-consistency=ON
gtid-mode=ON
[mysqld]
server-id=20
read_only=ON
enforce-gtid-consistency=ON
gtid-mode=ON
La configurazione di base per la replica del Master e' semplice: basta definire un server-id univoco ed indicare il nome dei file di log binario.
Anche la configurazione dello Slave e' semplice: server-id univoco e parametro read_only.

Altri parametri utili sono riportati nel seguito.

grant replication slave on *.* to 'repl'@'%' identified by 'xyz';  Non e' obbligatorio definire un nuovo utente ma e' consigliato sia per sicurezza che per semplicita' di configurazione e controllo
mysqladmin -p shutdownmysqladmin -p shutdown Bocce ferme
service mysql startservice mysql start Partiamo!
 reset master; Si, sullo slave!

Serve solo se lo slave non e' "pulito", va eseguito prima del restore per permettere di impostare i gtid_purged.

BackupRestore Le modalita' backup/restore sono molteplici e dipendono da diversi fattori.
Con un normale backup effettuato con: mysqldump --all-databases --triggers --routines --events --single-transaction ... ed il normale restore, vengono automaticamente impostati sul gtid_purged dello Slave i gtid_executed del Master
  change master to master_host='myMaster.MyDomain.it', master_user='repl', master_port=3306, master_password='xyz', master_auto_position=1; Con questo comando lo Slave sa come connettersi al Master e determina automaticamente da dove partire.
 start slave; Per far partire i thread dello Slave. Sono utilizzati un thread remoto (sul Master per inviare i bin-log) e due thread locali (per ricevere il bin-log ed applicarlo).
 show slave status\G Gia' fatto!

Non c'e' altro da configurare sullo slave si controlla lo stato della replica GTID.

I passi riportati e le spiegazioni sono un po' semplificati e ridondanti ma... rendono l'idea e funzionano per i casi principali (almeno spero ;-) E' ovvio che per far leggere i nuovi parametri del my.cnf e' necessario riavviare il server, che per lanciare uno statement SQL e' necessario collegarsi alla base dati, ...

Convertire in replica GTID

Potrebbe essere necessario effettuare la conversione da una replica file-based ad una replica con GTID. I passi sono differenti perche' le basi dati sono gia' allineate. Ci sono diverse alternative, vediamo la piu' semplice!

Attivita' sul Master
 
Attivita' sullo Slave
 
Note
 
SET @@global.read_only=ON;  Con questo comando si e' certi che sul master non avvengono modifiche.
mysqladmin -p shutdownmysqladmin -p shutdown Bocce ferme
[mysqld]
enforce-gtid-consistency=ON
gtid-mode=ON
[mysqld]
enforce-gtid-consistency=ON
gtid-mode=ON

skip-slave-start
Impostiamo i parametri relativi alla replica GTID nei file my.cnf.

Lo slave non e' ancora agganciato al Master e per questo va disattivato all'avvio: e' molto importante se si parte da una condizione di replica file-based.

service mysql startservice mysql start Partiamo!
  change master to master_host='myMaster.MyDomain.it', master_user='repl', master_port=3306, master_password='xyz', master_auto_position=1; Con questo comando lo Slave sa come connettersi al Master e determina automaticamente da dove partire.
 start slave; Per far partire i thread dello Slave. Sono utilizzati un thread remoto (sul Master per inviare i bin-log) e due thread locali (per ricevere il bin-log ed applicarlo).
SET @@global.read_only = OFF;show slave status\G Gia' fatto!

Il Master puo' essere riabilitato in scrittura e possono ripartire le applicazioni.
Non c'e' altro da configurare sullo slave si controlla lo stato della replica GTID.

 [mysqld]
# skip-slave-start
Non dimentichiamo di eliminare la direttiva sulla configurazione dello slave!

I passi riportati e le spiegazioni sono un po' semplificati ma... rendono l'idea (almeno spero ;-)

Conversione GTID online

Nel caso non sia possibile effettuare il riavvio dei DB e' utilizzabile una procedura per effettuare l'attivazione online del GTID.
In pratica i passi da eseguire su ogni server presente e da verificare prima di passare alla fase sucessiva sono:

SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN;    -- Controllare eventuali errori nel log
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;
SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;
SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;          -- SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT' deve andare a 0
FLUSH LOGS
SET @@GLOBAL.GTID_MODE = ON;                     -- Da impostare anche nel my.cnf con gtid-mode=ON
Quindi su ogni slave:
STOP SLAVE;
CHANGE MASTER TO MASTER_AUTO_POSITION = 1;
START SLAVE;

Come gia' indicato... non dimenticare di impostare i parametri corretti anche nel file my.cnf.

La procedura indicata e' disponibile dalla versione 5.7.6, la documentazione ufficiale riporta tutti i dettagli.

Ulteriori parametri di configurazione

La configurazione vista nel paragrafo precedente e' gia' perfettamente funzionante. Ulteriori parametri relativi alla replica in generale sono riportati in questo documento.
In questo breve capitolo descriviamo in modo compiuto i parametri relativi alla replicazione GTID.

Il parametro enforce-gtid-consistency puo' assumere i valori ON, OFF e WARN e va impostato ad ON per attivare la replica GTID.
gtid-mode assume i valori ON, OFF, OFF_PERMISSIVE, ON_PERMISSIVE
gtid-executed-compression-period che viene utilizzato per effettuare la compressione periodica della tabella mysql.gtid_executed se log_bin e' impostato ad OFF.

I parametri di configurazione utilizzabili, come abbiamo visto, sono molteplici... Per riassumere riportiamo una possibile configurazione finale che contiene tutti i parametri di interesse per la replica (compresi quelli che hanno un impatto sulle prestazioni). La configurazione e' relativa ad una semplice architettura in cui sono presenti un master ed uno slave configurati in replicazione GTID:

Parametri consigliati per la replica GTID
[mysqld]
server-id=N
log-bin=mysql-bin
relay_log=mysql-relay-bin
relay_log_index=mysql-relay-bin.index
enforce-gtid-consistency=ON
gtid-mode=ON
innodb_flush_log_at_trx_commit=1
sync_binlog=1
relay_log_info_repository=table
master_info_repository=table
report-host=Hostname
report-port=3306
expire_logs_days=8
slave-parallel-workers=4
slave-parallel-type=LOGICAL_CLOCK
slave_preserve_commit_order=1
# read_only=ON ### Su tutti gli slave
# super_read_only=ON ### Su tutti gli slave

Alcuni parametri sono specifici per Master/Slave, altri sono relativi alle performances, ... ma e' opportuno che le configurazioni siano allineate tra loro per disporre delle stesse performance in caso di switchover.

Avvertenze per l'uso

Anche se molto potente, la replicazione di MySQL ha alcuni limiti che non consentono di replicare tutto in tutti i casi... Le limitazioni della replica in generale sono descritte in questo documento e sul sito ufficiale.

Inoltre vi sono ulteriori limitazioni relative alla replica GTID dovute alla necessita' di serializzare le transazioni. Per evitare che la replica GTID si blocchi viene utilizzato il parametro enforce-gtid-consistency che fa fallire sul Master gli statement problematici.

Tra gli statement non corretti all'interno di una transazione per la replica GTID:

Errant transactions

Una errant transaction e' una transazione eseguita direttamente su uno slave anziche' sul master. Le errant transaction sono sempre esistite ma con la replica GTID generano problemi in caso di failover. Infatti viene mantenuta la lista dei GTID eseguiti ed il protocollo prevede lo scambio e l'esecuzione delle transazioni mancanti: durante il failover possono cosi' essere eseguite transazioni mai eseguite sul Master che possono bloccare la replica o, molto peggio, corrompere i dati senza alcun preavviso o segnalazione.

La prima cura contro le errant transaction e' la prevenzione: impostare in read_only gli Slave e tagliare le mani o i GRANT agli utenti troppo volenterosi [NdE super_read_only dalla 5.7.8] !!!

Per verificare la presenza di errant transaction si deve confrontare l'elenco dei GTID eseguiti sul Master e sugli Slave. I GTID eseguiti sugli Slave debbono essere un sottoinsieme di quelli eseguiti sul Master.

Quando le analisi sulle errant transaction danno risultato positivo e' necessario curarle subito con un'iniezione... e non e' una battuta!
E' necessario evitare che una errant transaction venga eseguita quando lo Slave su cui si e' operato diventa un Master. Per evitarlo si utilizza la tecnica di inserire una transazione con lo stesso GTID ma vuota sul master (che la replica sugli altri slave) o singolarmente sugli slave (se il master non c'e' piu'):

STOP SLAVE; SET GTID_NEXT="dadadace-1991-2ee2-a3a3-bababacecece:9"; BEGIN; COMMIT; SET GTID_NEXT="AUTOMATIC"; START SLAVE;

Questa tecnica (Empty Transaction Injection) e' utilizzabile anche per far "saltare" transazioni che danno errore su uno Slave. Infatti il parametro sql_slave_skip_counter non e' utilizzabile con il GTID.
Nel caso in cui le transazioni siano molte e si debba eseguire l'operazione su piu' slave si puo' lanciare un comando delle utility:
 mysqlslavetrx --gtid-set=dad..:9-69 --slaves=adm_repl:XXX@slave2:3312,adm_repl:XXX@slave3:3313

Per eliminare le errant transaction l'altra possibilita' e' quella di rimuovere i GTID indesiderati, ma e' un operativa che richiede piu' tempo: quindi non la descrivo. In ogni caso e' poi opportuna una verifica sulla consistenza dei dati.

Amministrazione

L'amministrazione di una replica con GTID e' analoga all'amministrazione della replica file-based ma alcune procedure sono semplificate.

Nell'operazione di switchover si vuole promuovere uno Slave (S2) a Master.

S2  SQL> STOP SLAVE IO_THREAD;

M1  SQL> CHANGE MASTER TO <new_master_def>;
M1  SQL> START SLAVE;

S1  SQL> STOP SLAVE IO_THREAD;
S1  SQL> CHANGE MASTER TO <new_master_def>;
S1  SQL> START SLAVE IO_THREAD;

La nuova configurazione e' immediatamente disponibile. Vanno solo reimpostati gli eventuali parametri READ_ONLY.

Qualche altro esempio? Nei due esempi seguenti viene resa evidente la semplificazione apportata con i GTID che non richiede la ricerca della posizione precisa del binlog ma la ricava in automatico. Aggiunta di un nuovo Slave:

# Classic Adding a new slave Master $ mysqldump -u root -p --all-databases --flush-privileges --single-transaction --flush-logs --triggers --routines --events --hex-blob > bck.sql Slave $ mysql -u root -p < bck.sql Slave $ head -n 100 bck.sql | grep "CHANGE MASTER TO" Slave SQL> CHANGE MASTER TO ... MASTER_LOG_FILE='mysql-bin.XXX', MASTER_LOG_POS=YYY; Slave SQL> START SLAVE; # GTID Adding a new slave Master $ mysqldump -u root -p --all-databases --flush-privileges --single-transaction --flush-logs --triggers --routines --events --hex-blob > bck.sql Slave $ mysql -u root -p < bck.sql Slave SQL> CHANGE MASTER TO ... MASTER_AUTO_POSITION=1; Slave SQL> START SLAVE;

Ripristino di un nuovo Slave che ha "perso la strada" (molto piu' semplice rispetto a quella della normale replica):

# Classic Restarting a broken Slave Master $ mysqldump -u root -p --all-databases --flush-privileges --single-transaction --master-data=2 --flush-logs --triggers --routines --events --hex-blob >bck.sq Slave $ mysql -u root -p < bck.sql Slave $ head -n 100 bck.sql | grep "CHANGE MASTER TO" Slave SQL> CHANGE MASTER TO ... MASTER_LOG_FILE='mysql-bin.XXX', MASTER_LOG_POS=YYY; Slave SQL> START SLAVE; # GTID Restarting a broken Slave Master $ mysqldump -u root -p --all-databases --flush-privileges --single-transaction --flush-logs --triggers --routines --events --hex-blob >bck.sql Slave SQL> RESET MASTER; Slave $ mysql -u root -p < bck.sql Slave SQL> START SLAVE;

Un ulteriore vantaggio della replica GTID e' quello che e' possibile utilizzare routine che effettuano in automatico tutte le operazioni necessarie su tutti gli slave e tenendo conto di tutte le condizioni (eg. Errant Transactions): continuate a leggere!

mysqlfailover

MySQL distribuisce una serie di utility tra cui mysqlfailover e mysqlrpladmin che sono utili per la gestione della replica GTID [NdA arch. link].

Lo script mysqlfailover opera su una configurazione anche complessa di replica con GTID effettuando in automatico le operazioni di failover o di switchover.

# Configurazione utente
grant all on *.* to adm_repl@'%' identified by 'XXX';
grant SUPER, GRANT OPTION, REPLICATION SLAVE, SELECT, RELOAD, DROP, CREATE, INSERT on *.* to adm_repl@'%' ;

# Visualizzazione la console
mysqlfailover -f auto --force --master=adm_repl:XXX@10.1.2.13:3306 --slaves=adm_repl:XXX@10.1.2.17:3306 --candidates=adm_repl:XXX@10.1.2.17:3306 
MySQL Replication Failover Utility Failover Mode = fail Next Interval = Wed Mar 16 16:14:16 2016 NOTICE: Failover mode changed to fail due to another instance of the console running against master. Master Information ------------------ Binary Log File Position Binlog_Do_DB Binlog_Ignore_DB mysql-bin.000007 71005 GTID Executed Set 677c206e-dfad-11e5-b112-005056bdc3aa:1-683071 [...] Replication Health Status +---------------+-------+---------+--------+------------+---------+ | host | port | role | state | gtid_mode | health | +---------------+-------+---------+--------+------------+---------+ | 10.1.2.13 | 3306 | MASTER | UP | ON | OK | | 10.1.2.17 | 3306 | SLAVE | UP | ON | OK | +---------------+-------+---------+--------+------------+---------+ Q-quit R-refresh H-health G-GTID Lists U-UUIDs

L'utilizzo piu' comune di mysqlfailover e' pero' con l'opzione --daemon che lo pone in background in attesa di un evento su cui intervenire. In molti casi e' necessario lanciare script (eg. riconfigurazione delle connessioni, attivazione VIP): questo e' possibile con i parametri exec-after, exec-before, ...
Per la normale amministrazione tipicamente si utilizza lo script mysqlrpladmin opera manualmente su una configurazione anche complessa di replica con GTID effettuando le operazioni di failover o di switchover occupandosi di lanciare tutti i comandi necessari su tutti i nodi coinvolti. Le opzioni dei due comandi sono analoghe.

Varie ed eventuali

La replica GTID implementata su MariaDB non e' compatibile con quella MySQL quindi non possono essere posti in replica GTID DB con MySQL e MariaDB.
La replica GTID e' compatibile con Galera Cluster, anzi presenta alcuni ulteriori vantaggi rispetto alla replica classica.


Titolo: MySQL GTID Replication
Livello: Avanzato (3/5)
Data: 1 Aprile 2015
Versione: 1.0.3 - 14 Febbraio 2016 ❤️ San Valentino
Autore: mail [AT] meo.bogliolo.name