
Il progresso non si ferma, quindi le ragioni per aggiornarsi alle versioni più recenti di MySQL stanno diventando sempre più rilevanti. Recentemente, in uno dei nostri progetti, è giunto il momento di aggiornare i confortevoli cluster di Percona Server 5.7 alla versione 8. Tutto ciò è avvenuto sulla piattaforma Ubuntu Linux 16.04. Come eseguire un'operazione del genere con il minimo downtime e quali problemi abbiamo incontrato durante l'aggiornamento — leggi in questo articolo.
Preparazione
Qualsiasi aggiornamento del server di database è probabilmente associato alla riconfigurazione del database: cambiamenti nei requisiti delle risorse di sistema e correzione dei file di configurazione del database, che devono essere ripuliti da direttive obsolete.
Prima dell'aggiornamento, ci consulteremo sempre con la documentazione ufficiale:
- ;
- ;
- ;
- .
E prepareremo un piano d'azione:
- Correggere i file di configurazione rimuovendo le direttive obsolete.
- Controllare la compatibilità con gli strumenti.
- Aggiornare i database slave, installando il pacchetto
percona-server-server. - Aggiornare il master, installando lo stesso pacchetto.
Analizziamo ogni punto del piano e vediamo cosa potrebbe andare storto.
IMPORTANTE! La procedura di aggiornamento del cluster MySQL basato su Galera ha le sue peculiarità, non descritte in questo articolo. Evita di utilizzare questa istruzione in tal caso.
Parte 1: Controllo dei file di configurazione
Nella versione 8 di MySQL è stato rimosso query_cache. In realtà era stato già nella versione 5.7, ma ora è stato . Pertanto, è necessario rimuovere le direttive associate. Per la memorizzazione nella cache delle query, ora è possibile utilizzare strumenti esterni, ad esempio, .
Sono state trovate anche direttive obsolete riguardanti innodb_file_format. Se nella versione 5.7 di MySQL era possibile scegliere il formato InnoDB, la versione 8 funziona già .
Il nostro risultato è la rimozione delle seguenti direttive:
-
query_cache_type,query_cache_limitequery_cache_size; -
innodb_file_formateinnodb_file_format_max.
Per il controllo utilizzeremo l'immagine Docker di Percona Server. Posizioneremo il file di configurazione del server nella directory mysql_config_test, e creeremo accanto le directory per i dati e i log. Esempio di test della configurazione di percona-server:
mkdir -p {mysql_config_test,mysql_data,mysql_logs}
cp -r /etc/mysql/conf.d/* mysql_config_test/
docker run --name some-percona -v $(pwd)/mysql_config_test:/etc/my.cnf.d/ -v $(pwd)/mysql_data/:/var/lib/mysql/ -v $(pwd)/mysql_logs/:/var/log/mysql/ -e MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD} -d percona:8-centosRisultato: apparirà un file, nei log di Docker o nella directory dei log — a seconda delle tue configurazioni — in cui saranno descritti i problemi relativi alle direttive.
Ecco cosa avevamo noi:
2020-04-03T12:44:19.670831Z 0 [Warning] [MY-011068] [Server] La sintassi 'expire-logs-days' è deprecata e sarà rimossa in una futura versione. Si prega di usare invece binlog_expire_logs_seconds.
2020-04-03T12:44:19.671678Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' è attualmente un alias per il set di caratteri UTF8MB3, ma sarà un alias per UTF8MB4 in una futura versione. Ti preghiamo di considerare di usare UTF8MB4 per evitare ambiguità.
2020-04-03T12:44:19.671682Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' è una collazione del set di caratteri deprecato UTF8MB3. Ti preghiamo di considerare di usare UTF8MB4 con una collation appropriata invece. Di conseguenza, abbiamo dovuto anche fare chiarezza sulle codifiche e sostituire la direttiva obsoleta expire-logs-days.
Parte 2: Controllo delle installazioni funzionanti
Nella documentazione di aggiornamento ci sono 2 strumenti per controllare il database per la compatibilità. Il loro utilizzo aiuta l'amministratore a verificare la compatibilità della struttura dati esistente.
Iniziamo con l'utilità classica mysqlcheck. È sufficiente lanciare:
mysqlcheck -u root -p --all-databases --check-upgradeSe non vengono trovati problemi, l'utilità si chiuderà con codice 0:

Inoltre, nelle moderne versioni di MySQL è disponibile l'utilità (nel caso di Percona è il pacchetto percona-mysql-shell). Essa sostituisce il classico cliente mysql e combina le funzioni di un client, di un editor di codice SQL e degli strumenti di amministrazione di MySQL. Per controllare il server prima dell'aggiornamento, puoi eseguire il seguente comando tramite essa:
mysqlsh -- util check-for-server-upgrade { --user=root --host=1.1.1.1 --port=3306 } --config-path=/etc/mysql/my.cnfEcco quali osservazioni abbiamo ricevuto:

In generale, nulla di critico — solo avvisi sulle codifiche (vedi sotto). Risultato finale dell'esecuzione:

Abbiamo ritenuto che l'aggiornamento dovesse procedere senza problemi.
Nota sugli avvisi precedenti, che indicano problemi con le codifiche. Il fatto è che fino a poco tempo fa UTF-8 in MySQL , in quanto memorizzava solo 3 byte invece di 4. In MySQL 8 finalmente : l'alias utf8 presto condurrà alla codifica utf8mb4, e le vecchie colonne delle tabelle diventeranno utf8mb3. In futuro, la codifica utf8mb3 verrà rimossa, ma non in questa release. Pertanto, abbiamo deciso di correggere le codifiche già sull'installazione attiva del DBMS, dopo il suo aggiornamento.
Parte 3: Aggiornamento dei server
Cosa può andare storto, quando c'è un piano così straordinario?.. Ben sapendo che i dettagli possono sempre presentarsi, abbiamo condotto il primo esperimento su un cluster MySQL dev.
Come già menzionato, tratta l'argomento dell'aggiornamento dei server MySQL con repliche. La questione si concentra sul fatto che prima bisognerebbe aggiornare tutte le repliche (slave), poiché MySQL 8 può replicare da un master con versione 5.7. Una certa complessità deriva dal fatto che utilizziamo la modalità master master, quando il master remoto è in modalità read-only. In altre parole, il traffico operativo fluisce in un data center, mentre il secondo funge da riserva.
La topologia appare come segue:

L'aggiornamento deve iniziare dalle repliche mysql replica dc 2, mysql master dc 2 e mysql replica dc 1, e terminare con il server mysql master dc 1. Per maggiore affidabilità, abbiamo spento le macchine virtuali, effettuato degli snapshot e, poco prima dell'aggiornamento, abbiamo fermato la replicazione con il comando STOP SLAVE. Per il resto, l'aggiornamento si presenta così:
- Riavviamo ogni replica, aggiungendo nei file di configurazione 3 opzioni:
skip-networking,skip-slave-start,skip-log-bin. Il motivo è che l'aggiornamento del database genera log binari con aggiornamenti delle tabelle di sistema. Queste direttive garantiscono che nel database non ci siano modifiche ai dati dell'applicazione e che nei log binari non venga registrata alcuna informazione sugli aggiornamenti delle tabelle di sistema. Questo eviterà problemi al ripristino della replicazione. - Installa il pacchetto
percona-server-server. È importante notare che nella versione MySQL 8 non è necessario eseguire il comandomysqlupgradedopo l'aggiornamento del server. - Dopo l'avvio riuscito, riavviamo nuovamente il server, senza le opzioni aggiunte al primo punto.
- Assicuriamoci che la replicazione funzioni correttamente: controlliamo
SHOW SLAVE STATUSe verifichiamo che le tabelle con i contatori nel database dell'applicazione si aggiornino.
Il tutto sembra abbastanza semplice: l'aggiornamento dev è andato a buon fine. Bene, possiamo pianificare tranquillamente l'aggiornamento notturno per la produzione.
Non è stato un problema — abbiamo aggiornato il prod
Tuttavia, trasferire il successo da dev a produzione non è stato privo di sorprese.
Fortunatamente, il processo di aggiornamento inizia dalle repliche, quindi, incontrando difficoltà, abbiamo interrotto i lavori e ripristinato la replica dallo snapshot. L'analisi dei problemi è stata rinviata al mattino successivo. I log contenevano le seguenti registrazioni:
2020-01-14T21:43:21.500563Z 2 [ERROR] [MY-012069] [InnoDB] table: t1 has 19 columns but InnoDB dictionary has 20 columns
2020-01-14T21:43:21.500722Z 2 [ERROR] [MY-010767] [Server] Error in fixing SE data for db1.t1
2020-01-14T21:43:24.208365Z 0 [ERROR] [MY-010022] [Server] Failed to Populate DD tables.
2020-01-14T21:43:24.208658Z 0 [ERROR] [MY-010119] [Server] Aborting L'analisi degli archivi di diverse newsletter su Google ha portato a comprendere che questo problema sorge a causa di . Anche se potrebbe essere considerato più un bug degli strumenti mysqlcheck e mysqlsh.
Si scopre che in MySQL hanno cambiato il modo di rappresentare i dati per i campi decimali (int, tinyint, ecc.), quindi all'interno di mysql-server viene utilizzato un diverso metodo di memorizzazione. Se il tuo database era originariamente nella versione 5.5 o 5.1, e successivamente hai aggiornato a 5.7, potrebbe essere necessario eseguire OPTIMIZE per alcune tabelle. Allora MySQL aggiornerà i file di dati, trasferendoli al formato di memorizzazione attuale.
Questo può anche essere verificato con lo strumento mysqlfrm:
mysqlfrm --diagnostic -vv /var/lib/mysql/db/table.frm
...
'field_length': 8,
'field_type': 246, # formato del campo
'field_type_name': 'decimal',
'flags': 3,
'flags_extra': 67,
'interval_nr': 0,
'name': 'your_decimal_column',
... Se field_type è 0, allora nella tabella viene utilizzato il tipo precedente — devi eseguire OPTIMIZE. Tuttavia, se è impostato su 246 — hai già il nuovo tipo. Maggiori informazioni sui tipi possono essere trovate in .
Inoltre, in viene considerata una seconda possibile causa, che ci ha evitato, riguardo all'assenza di tabelle InnoDB nella tabella di sistema INNODB_SYS_TABLESPACES, se queste ultime sono state create nella versione 5.1. Per evitare problemi durante l'aggiornamento, si può utilizzare .
Perché non abbiamo avuto tali problemi su dev? Il database viene periodicamente copiato dalla produzione — in questo modo, le tabelle vengono ricreate.
Sfortunatamente, su un grande database operativo non puoi semplicemente eseguire un vasto OPTIMIZE. Qui può aiutare percona-toolkit: per l'operazione online OPTIMIZE, l'utility pt-online-schema-change è molto utile.
Il piano aggiornato è diventato il seguente:
- Effettuare l'ottimizzazione di tutte le tabelle.
- Procedere all'aggiornamento dei database.
Per verificarlo e al contempo scoprire il tempo di aggiornamento, abbiamo disattivato una delle repliche e per tutte le tabelle abbiamo eseguito il seguente comando:
pt-online-schema-change --critical-load Threads_running=150 --alter "ENGINE=InnoDB" --execute --chunk-size 100 --quiet --alter-foreign-keys-method auto h=127.0.0.1,u=root,p=${MYSQL_PASSWORD},D=db1,t=t1L'aggiornamento delle tabelle avviene senza prolungati blocchi grazie al fatto che l'utility crea una nuova tabella temporanea, nella quale copia i dati dalla tabella principale. Nel momento in cui entrambe le tabelle sono identiche, la tabella originale viene bloccata e sostituita con la nuova. Nel nostro caso, il test ha mostrato che per aggiornare tutte le tabelle sono necessarie circa 24 ore, ma nel frattempo il trasferimento dei dati ha causato un carico eccessivo sui dischi.
Per evitare ciò, in produzione abbiamo aggiunto al comando l'argomento --sleep con un valore di 10: questo parametro regola la durata dell'attesa dopo il trasferimento di un blocco di dati nella nuova tabella. In questo modo è possibile ridurre il carico, se l'applicazione in esecuzione richiede tempi di risposta rapidi.
Dopo aver eseguito l'ottimizzazione, l'aggiornamento è avvenuto con successo.
… ma non fino in fondo!
Già dopo mezz'ora dall'aggiornamento, il cliente è arrivato con un problema. Il database si comportava in modo molto strano: occasionalmente si verificavano reset delle connessioni. Ecco come appariva nel monitoraggio:

Nello screenshot si vede un grafico a zig-zag, legato al fatto che alcuni flussi del server MySQL crollavano periodicamente con un errore. Nell'applicazione sono comparsi errori:
[PDOException] SQLSTATE[HY000] [2002] Connessione rifiutataUna rapida revisione dei log ha rivelato che il demone mysqld non riusciva ad ottenere le risorse necessarie dal sistema operativo. Indagando sugli errori, abbiamo scoperto nel sistema file di policy apparmor 'orfani':
# dpkg -S /etc/apparmor.d/cache/usr.sbin.mysqld
dpkg-query: no path found matching pattern /etc/apparmor.d/cache/usr.sbin.mysqld
# dpkg -S /etc/apparmor.d/local/usr.sbin.mysqld
dpkg-query: no path found matching pattern /etc/apparmor.d/local/usr.sbin.mysqld
# dpkg -S /etc/apparmor.d/usr.sbin.mysqld
mysql-server-5.7: /etc/apparmor.d/usr.sbin.mysqld
# dpkg -l mysql-server-5.7
rc mysql-server-5.7 5.7.23-0ubuntu0.16.04.1 amd64Questi file si erano formati durante l'aggiornamento a MySQL 5.7 un paio di anni fa e appartengono a un pacchetto rimosso. La rimozione dei file e il riavvio del servizio apparmor hanno risolto il problema:
systemctl stop apparmor
rm /etc/apparmor.d/cache/usr.sbin.mysqld
rm /etc/apparmor.d/local/usr.sbin.mysqld
rm /etc/apparmor.d/usr.sbin.mysqld
systemctl start apparmorIn conclusione
Qualsiasi operazione, anche la più semplice, può portare a problemi inaspettati. E anche avere un piano ben pensato non garantisce sempre un risultato previsto. Ora, in qualsiasi piano di aggiornamento, il nostro team include anche la pulizia obbligatoria dei file superflui che potrebbero essere apparsi a seguito di azioni precedenti.
E con questa creazione grafica non molto professionale, vorrei ringraziare l'azienda Percona per i loro ottimi prodotti!

P.S.
Leggete anche nel nostro blog:
- «»;
- «»;
- «»;
- «»;
- «».
Fonte: habr.com
