Gli slave MySQL potrebbero diventare incoerenti. Puoi provare a evitarlo, ma è davvero difficile. L'impostazione di super_read_only e l'utilizzo della replica basata su riga possono aiutare molto, ma qualunque cosa tu faccia, è comunque possibile che il tuo slave diventi incoerente.
Cosa si può fare per ricostruire uno slave MySQL incoerente? In questo post del blog daremo un'occhiata a questo problema.
Prima di tutto, discutiamo di cosa deve succedere per ricostruire uno schiavo. Per portare un nodo in MySQL Replication, deve essere fornito con i dati da uno dei nodi nella topologia di replica. Questi dati devono essere coerenti nel momento in cui sono stati raccolti. Non puoi prenderlo su una tabella per tabella o schema per schema, perché ciò renderà il nodo di cui è stato eseguito il provisioning incoerente internamente. Ciò significa che alcuni dati sarebbero più vecchi di altre parti del set di dati.
Oltre alla coerenza dei dati, dovrebbe anche essere possibile raccogliere informazioni sulla relazione tra i dati e lo stato di replica. Vuoi avere una posizione del log binario in cui i dati raccolti sono coerenti o l'ID transazione globale della transazione che è stata l'ultima eseguita sul nodo che è l'origine dei dati.
Questo ci porta alle seguenti considerazioni. È possibile ricostruire uno slave utilizzando qualsiasi strumento di backup purché questo strumento sia in grado di generare un backup coerente e includa le coordinate di replica per il momento in cui il backup è coerente. Questo ci consente di scegliere tra un paio di opzioni.
Utilizzo di Mysqldump per ricostruire uno slave MySQL incoerente
Mysqldump è lo strumento più basilare che abbiamo per raggiungere questo obiettivo. Ci consente di creare un backup logico, tra l'altro, sotto forma di istruzioni SQL. Ciò che è importante, pur essendo di base, ci consente comunque di eseguire un backup coerente:può utilizzare la transazione per garantire che i dati siano coerenti all'inizio della transazione. Può anche annotare le coordinate di replica per quel punto, anche un'intera istruzione CHANGE MASTER, facilitando l'avvio della replica utilizzando il backup.
Utilizzo di Mydumper per ricostruire uno slave MySQL incoerente
Un'altra opzione è usare mydumper:questo strumento, proprio come mysqldump, genera un backup logico e, proprio come mysqldump, può essere utilizzato per creare un backup coerente del database. La principale differenza tra mydumper e mysqldump è che mydumper, se associato a myloader, può eseguire il dump e il ripristino dei dati in parallelo, migliorando il dump e, soprattutto, il tempo di ripristino.
Utilizzo di uno snapshot per ricostruire uno slave MySQL incoerente
Per coloro che utilizzano provider cloud, una possibilità è quella di acquisire un'istantanea del block storage sottostante. Gli snapshot generano una vista puntuale dei dati. Tuttavia, questo processo è piuttosto complicato, poiché la consistenza dei dati e la capacità di ripristinarli dipendono principalmente dalla configurazione di MySQL.
Dovresti assicurarti che il database funzioni in una modalità durevole (è configurato in modo tale che il crash di MySQL non provochi alcuna perdita di dati). Questo perché (dal punto di vista di MySQL) acquisire un'istantanea del volume e quindi avviare un'altra istanza MySQL dai dati in essa archiviati è, fondamentalmente, lo stesso processo come se si uccidesse -9 mysqld e poi lo si riavviasse. Il ripristino di InnoDB deve avvenire, riprodurre le transazioni che sono state archiviate nei registri binari, le transazioni di rollback che non sono state completate prima dell'arresto anomalo e così via.
Lo svantaggio del processo di ricostruzione basato su snapshot è che è fortemente legato al fornitore attuale. Non è possibile copiare facilmente i dati delle istantanee da un provider cloud a un altro. Potresti essere in grado di spostarlo tra diverse regioni, ma sarà sempre lo stesso provider.
Utilizzo di Xtrabackup o Mariabackup per ricostruire uno slave MySQL incoerente
Infine, xtrabackup/mariabackup - questo è uno strumento scritto da Percona e forkato da MariaDB che permette di generare un backup fisico. È molto più veloce dei backup logici:è limitato principalmente dalle prestazioni hardware:disco o rete sono i colli di bottiglia più probabili. La maggior parte del carico di lavoro è correlata alla copia di file dalla directory dei dati di MySQL in un'altra posizione (sullo stesso host o sulla rete).
Anche se non è veloce quanto gli snapshot di archiviazione a blocchi, xtrabackup è molto più flessibile e può essere utilizzato in qualsiasi ambiente. Il backup che produce è costituito da file, quindi è perfettamente possibile copiare il backup in qualsiasi posizione desideri. Un altro fornitore di servizi cloud, il tuo datacenter locale, non importa fintanto che puoi trasferire file dalla tua posizione attuale.
Non deve nemmeno avere la connettività di rete:puoi anche copiare il backup su un dispositivo "trasferibile" come un SSD USB o persino una chiavetta USB, purché possa contenere tutti i dati e conservali in tasca mentre ti sposti da un datacenter all'altro.
Come ricostruire uno slave MySQL usando Xtrabackup?
Abbiamo deciso di concentrarci su xtrabackup, data la sua flessibilità e capacità di lavorare nella maggior parte degli ambienti in cui può esistere MySQL. Come ricostruisci il tuo slave usando xtrabackup? Diamo un'occhiata.
Inizialmente abbiamo un master e uno slave, che soffrivano di alcuni problemi di replica:
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.0.141
Master_User: rpl_user
Master_Port: 3306
Connect_Retry: 10
Master_Log_File: binlog.000004
Read_Master_Log_Pos: 386
Relay_Log_File: relay-bin.000008
Relay_Log_Pos: 363
Relay_Master_Log_File: binlog.000004
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 1007
Last_Error: Error 'Can't create database 'mytest'; database exists' on query. Default database: 'mytest'. Query: 'create database mytest'
Skip_Counter: 0
Exec_Master_Log_Pos: 195
Relay_Log_Space: 756
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 1007
Last_SQL_Error: Error 'Can't create database 'mytest'; database exists' on query. Default database: 'mytest'. Query: 'create database mytest'
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1001
Master_UUID: 53d96192-53f7-11ea-9c3c-080027c5bc64
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State:
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp: 200306 11:47:42
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: 53d96192-53f7-11ea-9c3c-080027c5bc64:9
Executed_Gtid_Set: 53d96192-53f7-11ea-9c3c-080027c5bc64:1-8,
ce7d0c38-53f7-11ea-9f16-080027c5bc64:1-3
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
Come puoi vedere, c'è un problema con uno degli schemi. Supponiamo di dover ricostruire questo nodo per riportarlo nella replica. Ecco i passaggi che dobbiamo eseguire.
Per prima cosa, dobbiamo assicurarci che xtrabackup sia installato. Nel nostro caso utilizziamo MySQL 8.0 quindi dobbiamo usare xtrabackup nella versione 8 per garantire la compatibilità:
[email protected]:~# apt install percona-xtrabackup-80
Reading package lists... Done
Building dependency tree
Reading state information... Done
percona-xtrabackup-80 is already the newest version (8.0.9-1.bionic).
0 upgraded, 0 newly installed, 0 to remove and 143 not upgraded.
Xtrabackup è fornito dal repository Percona e la guida per installarlo è disponibile qui:
https://www.percona.com/doc/percona-xtrabackup/8.0/installation/apt_repo.html
Lo strumento deve essere installato sia sul master che sullo slave che vogliamo ricostruire.
Come passaggio successivo rimuoveremo tutti i dati dallo slave "rotto":
[email protected]:~# service mysql stop
[email protected]:~# rm -rf /var/lib/mysql/*
Successivamente, prenderemo il backup sul master e lo trasmetteremo in streaming allo slave. Tieni presente che questo particolare one-liner richiede una connettività root SSH senza password dal master allo slave:
[email protected]:~# xtrabackup --backup --compress --stream=xbstream --target-dir=./ | ssh [email protected] "xbstream -x --decompress -C /var/lib/mysql/"
Alla fine dovresti vedere una riga importante:
200306 12:10:40 completed OK!
Questo è un indicatore che il backup è stato completato correttamente. Un paio di cose potrebbero ancora andare storte, ma almeno abbiamo i dati corretti. Successivamente, sullo slave, dobbiamo preparare il backup.
[email protected]:~# xtrabackup --prepare --target-dir=/var/lib/mysql/
.
.
.
200306 12:16:07 completed OK!
Dovresti vedere, ancora una volta, che il processo è stato completato correttamente. Potresti voler ora copiare nuovamente i dati nella directory dei dati di MySQL. Non è necessario farlo poiché abbiamo archiviato il backup in streaming direttamente in /var/lib/mysql. Quello che vogliamo fare, però, è garantire la corretta proprietà dei file:
[email protected]:~# chown -R mysql.mysql /var/lib/mysql
Ora controlliamo le coordinate GTID del backup. Li useremo in seguito durante l'impostazione della replica.
[email protected]:~# cat /var/lib/mysql/xtrabackup_binlog_info
binlog.000007 195 53d96192-53f7-11ea-9c3c-080027c5bc64:1-9
Ok, sembra tutto a posto, avviamo MySQL e procediamo con la configurazione della replica:
[email protected]:~# service mysql start
[email protected]:~# mysql -ppass
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.18-9 Percona Server (GPL), Release '9', Revision '53e606f'
Copyright (c) 2009-2019 Percona LLC and/or its affiliates
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
Ora dobbiamo impostare gtid_purged sul set GTID che abbiamo trovato nel backup. Quelli sono GTID che sono stati "coperti" dal nostro backup. Solo il nuovo GTID dovrebbe essere replicato dal master.
mysql> SET GLOBAL gtid_purged='53d96192-53f7-11ea-9c3c-080027c5bc64:1-9';
Query OK, 0 rows affected (0.00 sec)
Now we can start the replication:
mysql> CHANGE MASTER TO MASTER_HOST='10.0.0.141', MASTER_USER='rpl_user', MASTER_PASSWORD='yIPpgNE4KE', MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
mysql> START SLAVE;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.0.141
Master_User: rpl_user
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: binlog.000007
Read_Master_Log_Pos: 380
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 548
Relay_Master_Log_File: binlog.000007
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 380
Relay_Log_Space: 750
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1001
Master_UUID: 53d96192-53f7-11ea-9c3c-080027c5bc64
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: 53d96192-53f7-11ea-9c3c-080027c5bc64:10
Executed_Gtid_Set: 53d96192-53f7-11ea-9c3c-080027c5bc64:1-10
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
Come puoi vedere, il nostro schiavo si sta replicando dal suo padrone.
Come ricostruire uno slave MySQL utilizzando ClusterControl?
Se sei un utente ClusterControl, invece di eseguire questo processo puoi ricostruire lo slave in un paio di clic. Inizialmente abbiamo un chiaro problema con la replica:
Il nostro slave non si replica correttamente a causa di un errore.
Tutto ciò che dobbiamo fare è eseguire il lavoro "Rebuild Replication Slave" .
Ti verrà presentata una finestra di dialogo in cui dovresti scegliere un nodo master per lo schiavo che vuoi ricostruire. Quindi, fai clic su Procedi e sei pronto. ClusterControl ricostruirà lo slave e imposterà la replica per te.
A breve, in base alla dimensione del set di dati, dovresti vedere lo slave funzionante:
Come puoi vedere, con solo un paio di clic ClusterControl ha eseguito il compito di ricostruire lo slave di replica incoerente.