Mysql
 sql >> Database >  >> RDS >> Mysql

Risoluzione dei problemi di replica MySQL:parte prima

La replica è uno dei modi più comuni per ottenere un'elevata disponibilità per MySQL e MariaDB. È diventato molto più robusto con l'aggiunta di GTID ed è stato testato a fondo da migliaia e migliaia di utenti. MySQL Replication non è una proprietà "imposta e dimentica", tuttavia, deve essere monitorata per potenziali problemi e mantenuta in modo che rimanga in buone condizioni. In questo post del blog, vorremmo condividere alcuni suggerimenti e trucchi su come mantenere, risolvere e risolvere i problemi con la replica di MySQL.

Come determinare se la replica MySQL è in buone condizioni?

Questa è senza dubbio l'abilità più importante che chiunque si occupi di una configurazione di replica di MySQL deve possedere. Diamo un'occhiata a dove cercare informazioni sullo stato di replica. C'è una leggera differenza tra MySQL e MariaDB e ne parleremo anche.

MOSTRA LO STATO SLAVE

Questo è senza dubbio il metodo più comune per controllare lo stato della replica su un host slave:è con noi da sempre e di solito è il primo posto in cui andiamo se ci aspettiamo che ci siano problemi con la replica.

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.0.101
                  Master_User: rpl_user
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: binlog.000002
          Read_Master_Log_Pos: 767658564
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 405
        Relay_Master_Log_File: binlog.000002
             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: 767658564
              Relay_Log_Space: 606
              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: 1
                  Master_UUID: 5d1e2227-07c6-11e7-8123-080027495a77
             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:
            Executed_Gtid_Set: 5d1e2227-07c6-11e7-8123-080027495a77:1-394233
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.00 sec)

Alcuni dettagli possono differire tra MySQL e MariaDB, ma la maggior parte del contenuto avrà lo stesso aspetto. Le modifiche saranno visibili nella sezione GTID poiché MySQL e MariaDB lo fanno in un modo diverso. Da SHOW SLAVE STATUS, puoi ricavare alcune informazioni - quale master viene utilizzato, quale utente e quale porta viene utilizzata per connettersi al master. Abbiamo alcuni dati sull'attuale posizione del log binario (non più così importante poiché possiamo usare GTID e dimenticare i binlog) e lo stato dei thread di replica SQL e I/O. Quindi puoi vedere se e come è configurato il filtro. Puoi anche trovare alcune informazioni su errori, ritardo di replica, impostazioni SSL e GTID. L'esempio sopra viene dallo slave MySQL 5.7 che è in uno stato integro. Diamo un'occhiata ad alcuni esempi in cui la replica è interrotta.

MariaDB [test]> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.0.104
                  Master_User: rpl_user
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: binlog.000003
          Read_Master_Log_Pos: 636
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 765
        Relay_Master_Log_File: binlog.000003
             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: 1032
                   Last_Error: Could not execute Update_rows_v1 event on table test.tab; Can't find record in 'tab', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log binlog.000003, end_log_pos 609
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 480
              Relay_Log_Space: 1213
              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: 1032
               Last_SQL_Error: Could not execute Update_rows_v1 event on table test.tab; Can't find record in 'tab', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log binlog.000003, end_log_pos 609
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
               Master_SSL_Crl:
           Master_SSL_Crlpath:
                   Using_Gtid: Slave_Pos
                  Gtid_IO_Pos: 0-1-73243
      Replicate_Do_Domain_Ids:
  Replicate_Ignore_Domain_Ids:
                Parallel_Mode: conservative
1 row in set (0.00 sec)

Questo esempio è tratto da MariaDB 10.1, puoi vedere le modifiche nella parte inferiore dell'output per farlo funzionare con i GTID di MariaDB. Ciò che è importante per noi è l'errore:puoi vedere che qualcosa non va nel thread SQL:

Last_SQL_Error: Could not execute Update_rows_v1 event on table test.tab; Can't find record in 'tab', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log binlog.000003, end_log_pos 609

Discuteremo questo particolare problema più avanti, per ora è sufficiente vedere come verificare se ci sono errori nella replica utilizzando SHOW SLAVE STATUS.

Un'altra informazione importante che deriva da SHOW SLAVE STATUS è:quanto gravemente è in ritardo il nostro schiavo. Puoi verificarlo nella colonna "Seconds_Behind_Master". Questa metrica è particolarmente importante da monitorare se sai che la tua applicazione è sensibile quando si tratta di letture non aggiornate.

In ClusterControl puoi tenere traccia di questi dati nella sezione "Panoramica":

Abbiamo reso visibili tutte le informazioni più importanti dal comando SHOW SLAVE STATUS. È possibile controllare lo stato della replica, chi è il master, se c'è un ritardo di replica o meno, posizioni del log binario. Puoi anche trovare GTID recuperati ed eseguiti.

Schema delle prestazioni

Un altro posto in cui puoi cercare le informazioni sulla replica è performance_schema. Questo vale solo per MySQL 5.7 di Oracle:le versioni precedenti e MariaDB non raccolgono questi dati.

mysql> SHOW TABLES FROM performance_schema LIKE 'replication%';
+---------------------------------------------+
| Tables_in_performance_schema (replication%) |
+---------------------------------------------+
| replication_applier_configuration           |
| replication_applier_status                  |
| replication_applier_status_by_coordinator   |
| replication_applier_status_by_worker        |
| replication_connection_configuration        |
| replication_connection_status               |
| replication_group_member_stats              |
| replication_group_members                   |
+---------------------------------------------+
8 rows in set (0.00 sec)

Di seguito puoi trovare alcuni esempi di dati disponibili in alcune di queste tabelle.

mysql> select * from replication_connection_status\G
*************************** 1. row ***************************
             CHANNEL_NAME:
               GROUP_NAME:
              SOURCE_UUID: 5d1e2227-07c6-11e7-8123-080027495a77
                THREAD_ID: 32
            SERVICE_STATE: ON
COUNT_RECEIVED_HEARTBEATS: 1
 LAST_HEARTBEAT_TIMESTAMP: 2017-03-17 19:41:34
 RECEIVED_TRANSACTION_SET: 5d1e2227-07c6-11e7-8123-080027495a77:715599-724966
        LAST_ERROR_NUMBER: 0
       LAST_ERROR_MESSAGE:
     LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
1 row in set (0.00 sec)
mysql> select * from replication_applier_status_by_worker\G
*************************** 1. row ***************************
         CHANNEL_NAME:
            WORKER_ID: 0
            THREAD_ID: 31
        SERVICE_STATE: ON
LAST_SEEN_TRANSACTION: 5d1e2227-07c6-11e7-8123-080027495a77:726086
    LAST_ERROR_NUMBER: 0
   LAST_ERROR_MESSAGE:
 LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
1 row in set (0.00 sec)

Come puoi vedere, possiamo verificare lo stato della replica, l'ultimo errore, il set di transazioni ricevuto e alcuni altri dati. Ciò che è importante:se hai abilitato la replica multi-thread, nella tabella replication_applier_status_by_worker vedrai lo stato di ogni singolo lavoratore:questo ti aiuta a comprendere lo stato della replica per ciascuno dei thread di lavoro.

Ritardo di replica

Il ritardo è sicuramente uno dei problemi più comuni che dovrai affrontare quando lavori con la replica di MySQL. Il ritardo di replica si verifica quando uno degli slave non è in grado di tenere il passo con la quantità di operazioni di scrittura eseguite dal master. I motivi potrebbero essere diversi:diversa configurazione hardware, carico più pesante sullo slave, alto grado di parallelizzazione della scrittura sul master che deve essere serializzato (quando si utilizza un thread singolo per la replica) o le scritture non possono essere parallelizzate nella stessa misura in cui ha stato sul master (quando utilizzi la replica multi-thread).

Come rilevarlo?

Esistono due metodi per rilevare il ritardo di replica. Prima di tutto, puoi selezionare "Seconds_Behind_Master" nell'output SHOW SLAVE STATUS - ti dirà se lo slave è in ritardo o meno. Funziona bene nella maggior parte dei casi, ma nelle topologie più complesse, quando si utilizzano master intermedi, su host in un punto basso nella catena di replica, potrebbe non essere preciso. Un'altra soluzione migliore è affidarsi a strumenti esterni come pt-heartbeat. L'idea è semplice:viene creata una tabella con, tra l'altro, una colonna timestamp. Questa colonna viene aggiornata sul master a intervalli regolari. Su uno slave, puoi quindi confrontare il timestamp di quella colonna con l'ora corrente:ti dirà quanto è indietro lo slave.

Indipendentemente dal modo in cui calcoli il ritardo, assicurati che i tuoi host siano sincronizzati nel tempo. Usa ntpd o altri mezzi per sincronizzare il tempo:se c'è una deriva temporale, vedrai un ritardo "falso" sui tuoi slave.

Come ridurre il ritardo?

Questa non è una domanda facile a cui rispondere. In breve, dipende da cosa sta causando il ritardo e da cosa è diventato un collo di bottiglia. Esistono due modelli tipici:lo slave è legato all'I/O, il che significa che il suo sottosistema I/O non è in grado di far fronte alla quantità di operazioni di scrittura e lettura. Secondo:lo slave è vincolato alla CPU, il che significa che il thread di replica utilizza tutta la CPU possibile (un thread può utilizzare solo un core della CPU) e non è ancora sufficiente per gestire tutte le operazioni di scrittura.

Quando la CPU è un collo di bottiglia, la soluzione può essere semplice come utilizzare la replica multi-thread. Aumentare il numero di thread di lavoro per consentire una maggiore parallelizzazione. Tuttavia non è sempre possibile - in tal caso potresti voler giocare un po' con le variabili di commit di gruppo (sia per MySQL che per MariaDB) per ritardare i commit per un leggero periodo di tempo (stiamo parlando di millisecondi qui) e, in questo modo , aumentare la parallelizzazione dei commit.

Se il problema è nell'I/O, il problema è un po' più difficile da risolvere. Ovviamente, dovresti rivedere le tue impostazioni I/O di InnoDB - forse c'è spazio per miglioramenti. Se my.cnf tuning non ti aiuta, non hai molte opzioni:migliora le tue query (ove possibile) o aggiorna il tuo sottosistema I/O a qualcosa di più capace.

La maggior parte dei proxy (ad esempio, tutti i proxy che possono essere distribuiti da ClusterControl:ProxySQL, HAProxy e MaxScale) offrono la possibilità di rimuovere uno slave dalla rotazione se il ritardo di replica supera una soglia predefinita. Questo non è affatto un metodo per ridurre il ritardo, ma può essere utile per evitare letture obsolete e, come effetto collaterale, per ridurre il carico su uno slave che dovrebbe aiutarlo a recuperare il ritardo.

Naturalmente, l'ottimizzazione delle query può essere una soluzione in entrambi i casi:è sempre utile migliorare le query che richiedono un elevato carico di CPU o I/O.

Transazioni errate

Le transazioni errate sono transazioni eseguite solo su uno slave, non sul master. Insomma, fanno uno schiavo incoerente con il padrone. Quando si utilizza la replica basata su GTID, ciò può causare seri problemi se lo slave viene promosso a master. Abbiamo un post approfondito su questo argomento e ti invitiamo a esaminarlo e a familiarizzare con come rilevare e risolvere i problemi con le transazioni errate. Sono state incluse anche informazioni su come ClusterControl rileva e gestisce le transazioni errate.

Nessun file Binlog sul Master

Come identificare il problema?

In alcune circostanze, può accadere che uno slave si connetta a un master e richieda un file di registro binario inesistente. Una delle ragioni potrebbe essere la transazione errata:a un certo punto, una transazione è stata eseguita su uno slave e in seguito questo slave diventa un master. Altri host, che sono configurati per assolvere a quel master, chiederanno la transazione mancante. Se è stato eseguito molto tempo fa, è possibile che i file di registro binari siano già stati eliminati.

Un altro esempio più tipico:si desidera eseguire il provisioning di uno slave utilizzando xtrabackup. Si copia il backup su un host, si applica il registro, si cambia il proprietario della directory dei dati di MySQL:operazioni tipiche che si eseguono per ripristinare un backup. Tu esegui

SET GLOBAL gtid_purged=

in base ai dati di xtrabackup_binlog_info ed esegui CHANGE MASTER TO … MASTER_AUTO_POSITION=1 (questo è in MySQL, MariaDB ha un processo leggermente diverso), avvia lo slave e poi finisci con un errore come:

                Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'

in MySQL o:

                Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find GTID state requested by slave in any binlog files. Probably the slave state is too old and required binlog files have been purged.'

in MariaDB.

Ciò significa sostanzialmente che il master non ha tutti i registri binari necessari per eseguire tutte le transazioni mancanti. Molto probabilmente, il backup è troppo vecchio e il master ha già eliminato alcuni dei log binari creati tra il momento in cui è stato creato il backup e il momento in cui è stato eseguito il provisioning dello slave.

Come risolvere questo problema?

Sfortunatamente, non c'è molto che puoi fare in questo caso particolare. Se disponi di alcuni host MySQL che memorizzano i log binari per un tempo più lungo rispetto al master, puoi provare a utilizzare quei log per riprodurre le transazioni mancanti sullo slave. Diamo un'occhiata a come si può fare.

Prima di tutto, diamo un'occhiata al GTID più vecchio nei log binari del master:

mysql> SHOW BINARY LOGS\G
*************************** 1. row ***************************
 Log_name: binlog.000021
File_size: 463
1 row in set (0.00 sec)

Quindi, "binlog.000021" è l'ultimo (e unico) file. Controlliamo qual è la prima voce GTID in questo file:

[email protected]:~# mysqlbinlog /var/lib/mysql/binlog.000021
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @[email protected]@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#170320 10:39:51 server id 1  end_log_pos 123 CRC32 0x5644fc9b     Start: binlog v 4, server v 5.7.17-11-log created 170320 10:39:51
# Warning: this binlog is either in use or was not closed properly.
BINLOG '
d7HPWA8BAAAAdwAAAHsAAAABAAQANS43LjE3LTExLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
AZv8RFY=
'/*!*/;
# at 123
#170320 10:39:51 server id 1  end_log_pos 194 CRC32 0x5c096d62     Previous-GTIDs
# 5d1e2227-07c6-11e7-8123-080027495a77:1-1106668
# at 194
#170320 11:21:26 server id 1  end_log_pos 259 CRC32 0xde21b300     GTID    last_committed=0    sequence_number=1
SET @@SESSION.GTID_NEXT= '5d1e2227-07c6-11e7-8123-080027495a77:1106669'/*!*/;
# at 259

Come possiamo vedere, la voce di log binario più vecchia disponibile è:5d1e2227-07c6-11e7-8123-080027495a77:1106669

Dobbiamo anche verificare qual è l'ultimo GTID coperto nel backup:

[email protected]:~# cat /var/lib/mysql/xtrabackup_binlog_info
binlog.000017    194    5d1e2227-07c6-11e7-8123-080027495a77:1-1106666

È:5d1e2227-07c6-11e7-8123-080027495a77:1-1106666 quindi mancano due eventi:
5d1e2227-07c6-11e7-8123-080027495a77:1106667-1106668

Vediamo se riusciamo a trovare quelle transazioni su altri slave.

mysql> SHOW BINARY LOGS;
+---------------+------------+
| Log_name      | File_size  |
+---------------+------------+
| binlog.000001 | 1074130062 |
| binlog.000002 |  764366611 |
| binlog.000003 |  382576490 |
+---------------+------------+
3 rows in set (0.00 sec)

Sembra che "binlog.000003" sia l'ultimo registro binario. Dobbiamo verificare se i nostri GTID mancanti possono essere trovati in esso:

slave2:~# mysqlbinlog /var/lib/mysql/binlog.000003 | grep "5d1e2227-07c6-11e7-8123-080027495a77:110666[78]"
SET @@SESSION.GTID_NEXT= '5d1e2227-07c6-11e7-8123-080027495a77:1106667'/*!*/;
SET @@SESSION.GTID_NEXT= '5d1e2227-07c6-11e7-8123-080027495a77:1106668'/*!*/;

Tieni presente che potresti voler copiare i file binlog al di fuori del server di produzione poiché elaborarli può aggiungere del carico. Dopo aver verificato l'esistenza di tali GTID, possiamo estrarli:

slave2:~# mysqlbinlog --exclude-gtids='5d1e2227-07c6-11e7-8123-080027495a77:1-1106666,5d1e2227-07c6-11e7-8123-080027495a77:1106669' /var/lib/mysql/binlog.000003 > to_apply_on_slave1.sql

Dopo un rapido scp, possiamo applicare quegli eventi sullo slave

slave1:~# mysql -ppass < to_apply_on_slave1.sql

Una volta fatto, possiamo verificare se quei GTID sono stati applicati esaminando l'output di SHOW SLAVE STATUS:

                Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
                  Master_UUID: 5d1e2227-07c6-11e7-8123-080027495a77
             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: 170320 10:45:04
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set: 5d1e2227-07c6-11e7-8123-080027495a77:1-1106668

Executed_GTID_set sembra buono, quindi possiamo avviare thread slave:

mysql> START SLAVE;
Query OK, 0 rows affected (0.00 sec)

Controlliamo se ha funzionato bene. Useremo, ancora una volta, l'output SHOW SLAVE STATUS:

           Master_SSL_Crlpath:
           Retrieved_Gtid_Set: 5d1e2227-07c6-11e7-8123-080027495a77:1106669
            Executed_Gtid_Set: 5d1e2227-07c6-11e7-8123-080027495a77:1-1106669

Sembra buono, è installato e funzionante!

Un altro metodo per risolvere questo problema sarà eseguire un backup ancora una volta ed eseguire nuovamente il provisioning dello slave, utilizzando nuovi dati. Questo sarà molto probabilmente più veloce e sicuramente più affidabile. Non capita spesso di avere politiche di eliminazione binlog diverse su master e slave)

Continueremo a discutere di altri tipi di problemi di replica nel prossimo post del blog.