
Il progresso non si ferma, quindi le ragioni per aggiornarsi alle versioni attuali di MySQL diventano sempre più rilevanti. Non molto tempo fa, in uno dei nostri progetti, è arrivato 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 questa operazione con un minimo di inattesa e quali problemi abbiamo incontrato durante l'aggiornamento — leggi in questo articolo.
Preparazione
Qualsiasi aggiornamento di un server di database è probabilmente legato alla riconfigurazione del database: cambiamenti nei requisiti sui limiti delle risorse di sistema e correzioni nei file di configurazione del database, che devono essere ripuliti da direttive obsolete.
Prima dell'aggiornamento, ci riferiremo necessariamente alla documentazione ufficiale:
- ;
- ;
- ;
- .
E prepareremo un piano d'azione:
- Correggere i file di configurazione, rimuovendo le direttive obsolete.
- Controllare la compatibilità con utilità.
- Aggiornare i database slave, installando il pacchetto
percona-server-server. - Aggiornare il master, installando lo stesso pacchetto.
Analizzeremo ogni punto del piano e vedremo cosa potrebbe non andare per il verso giusto.
IMPORTANTE! La procedura di aggiornamento di un cluster MySQL basato su Galera ha le sue particolarità, che non sono descritte in questo articolo. Non utilizzare questa istruzione in tal caso.
Parte 1: Controllo dei file di configurazione
Nella versione 8 di MySQL è stato rimosso query_cache. In effetti, era stato già nella versione 5.7, ma ora è stato anche . Pertanto, è necessario rimuovere le direttive correlate. E per la memorizzazione nella cache delle query, ora si possono utilizzare strumenti esterni, come ad esempio, .
Nel file di configurazione 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 ora funziona .
Il nostro risultato è la rimozione delle seguenti direttive:
-
query_cache_type,query_cache_limitequery_cache_size; -
innodb_file_formateinnodb_file_format_max.
Per la verifica ci avvaleremo di un'immagine Docker di Percona Server. Posizioneremo la configurazione del server nella directory mysql_config_test, e accanto creeremo directory per i dati e i log. Esempio di test della configurazione 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: o nei log di Docker, o nella directory dei log — a seconda delle vostre configurazioni — apparirà un file che descrive le direttive problematiche.
Ecco cosa avevamo noi:
2020-04-03T12:44:19.670831Z 0 [Warning] [MY-011068] [Server] La sintassi 'expire-logs-days' è deprecata e verrà rimossa in un futuro rilascio. Si prega di utilizzare binlog_expire_logs_seconds invece.
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 diventerà un alias per UTF8MB4 in un futuro rilascio. Si prega di considerare l'uso di UTF8MB4 per evitare ambiguità.
2020-04-03T12:44:19.671682Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' è una collation del set di caratteri deprecato UTF8MB3. Si prega di considerare l'uso di UTF8MB4 con una collation appropriata invece. Pertanto, abbiamo dovuto esaminare anche le codifiche e sostituire la direttiva obsoleta expire-logs-days.
Parte 2: Verifica delle installazioni attive
Nella documentazione dell'aggiornamento ci sono 2 utility per controllare la compatibilità del database. Il loro utilizzo aiuta l'amministratore a verificare la compatibilità dell'attuale struttura dei dati.
Iniziamo con l'utility classica mysqlcheck. È sufficiente eseguirla:
mysqlcheck -u root -p --all-databases --check-upgradeSe non vengono rilevati problemi, l'utility terminerà con codice 0:

Inoltre, nelle versioni moderne di MySQL è disponibile l'utility (nel caso di Percona è il pacchetto percona-mysql-shell). Essa sostituisce il client mysql classico e combina le funzioni di un client, un editor di codice SQL e strumenti di amministrazione di MySQL. Per controllare il server prima dell'aggiornamento, è possibile eseguire il seguente comando attraverso di 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, non c'è nulla di critico — solo avvisi riguardanti le codifiche. (vedi sotto)Il risultato complessivo dell'esecuzione:

Abbiamo deciso che l'aggiornamento dovrebbe procedere senza problemi.
Nota sugli avvisi sopra, che indicano problemi con le codifiche. Infatti, UTF-8 in MySQL fino a poco tempo fa , poiché memorizzava solo 3 byte invece di 4. In MySQL 8 finalmente : l'alias utf8 presto condurrà alla codifica utf8mb4, mentre le vecchie colonne nelle tabelle diventeranno utf8mb3.In futuro, la codifica utf8mb3. verrà rimossa, ma non in questa versione. Pertanto, abbiamo deciso di correggere le codifiche già nell'installazione attiva del DBMS, dopo il suo aggiornamento.
Parte 3: Aggiornamento dei server
Cosa potrebbe andare storto quando c'è un piano così fantastico?.. Ben consapevoli che i dettagli possono sempre causare problemi, abbiamo condotto il primo esperimento su un cluster MySQL di sviluppo.
Come già menzionato, illustra la questione dell'aggiornamento dei server MySQL con repliche. Il concetto principale è che prima di tutto è necessario aggiornare tutte le repliche (slave), poiché MySQL 8 è in grado di replicare da un master della versione 5.7. Una certa complessità deriva dal fatto che utilizziamo la modalità master master, quando il master remoto è in modalità read-only. Cioè, di fatto, il traffico operativo arriva in un datacenter, mentre il secondo funge da backup.
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 concludersi con il server mysql master dc 1. Per maggiore sicurezza abbiamo spento le macchine virtuali, abbiamo effettuato dei snapshot e immediatamente prima dell'aggiornamento abbiamo fermato la replicazione con il comando STOP SLAVE. In tutto il resto, l'aggiornamento procede come segue:
- Riavviamo ogni replica, aggiungendo 3 opzioni ai file di configurazione:
skip-networking,skip-slave-start,skip-log-bin. Il fatto è che l'aggiornamento del database genera log binari con l'aggiornamento 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 l'informazione sull'aggiornamento delle tabelle di sistema. Questo eviterà problemi al momento della ripresa della replicazione. - Installiamo il pacchetto
percona-server-server. È importante sottolineare che nella versione MySQL 8 non è necessario avviare il comandomysqlupgradedopo l'aggiornamento del server. - Dopo l'avvio riuscito, riavviamo di nuovo il server — senza i parametri aggiunti nel primo punto.
- Ci assicuriamo che la replicazione funzioni correttamente: controlliamo
SHOW SLAVE STATUSe verifichiamo che le tabelle con i contatori nel database dell'applicazione si stiano aggiornando.
Tutto ciò sembra piuttosto semplice: l'aggiornamento del dev è andato a buon fine. Ok, possiamo pianificare tranquillamente l'aggiornamento notturno per la produzione.
Nessun problema — abbiamo aggiornato la prod
Tuttavia, trasferire l'esperienza positiva del dev alla produzione non è stato privo di sorprese.
Fortunatamente, il processo di aggiornamento inizia dalle repliche, quindi, di fronte a delle difficoltà, abbiamo interrotto i lavori e ripristinato la replica dallo snapshot. L'analisi dei problemi è stata rinviata alla mattina successiva. Nei log sono emerse le seguenti registrazioni:
2020-01-14T21:43:21.500563Z 2 [ERRORE] [MY-012069] [InnoDB] tabella: t1 ha 19 colonne ma il dizionario InnoDB ha 20 colonne
2020-01-14T21:43:21.500722Z 2 [ERRORE] [MY-010767] [Server] Errore durante la correzione dei dati SE per db1.t1
2020-01-14T21:43:24.208365Z 0 [ERRORE] [MY-010022] [Server] Impossibile popolare le tabelle DD.
2020-01-14T21:43:24.208658Z 0 [ERRORE] [MY-010119] [Server] Aborto L'esame degli archivi di diverse mailing list su Google ha portato a comprendere che un tale problema si verifica a causa di . Anche se in realtà è 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 del mysql-server viene utilizzato un altro metodo di archiviazione. Se il tuo database inizialmente era nella versione 5.5 o 5.1 e poi sei stato aggiornato alla 5.7, potrebbe essere necessario eseguire Se nella partizione è rimasto solo un pezzo, non si può avviare la fusione con il comando normale, è necessario utilizzare per alcune tabelle. Allora MySQL aggiornerà i file con i dati, convertendoli nel formato di archiviazione attuale.
Questo può essere verificato anche con l'utility mysqlfrm:
mysqlfrm --diagnostic -vv /var/lib/mysql/db/table.frm
...
'field_length': 8,
'field_type': 246, # formato campo
'field_type_name': 'decimal',
'flags': 3,
'flags_extra': 67,
'interval_nr': 0,
'name': 'your_decimal_column',
... Se field_type è uguale a 0, allora nella tabella viene utilizzato il vecchio tipo — è necessario effettuare Se nella partizione è rimasto solo un pezzo, non si può avviare la fusione con il comando normale, è necessario utilizzare. Tuttavia, se il valore è 246 — hai già un nuovo tipo. Puoi scoprire di più sui tipi in .
Inoltre, in viene considerata una seconda possibile causa, che ci ha sorvolato, ovvero l'assenza di tabelle InnoDB nella tabella di sistema INNODB_SYS_TABLESPACES, se queste tabelle sono state create nella versione 5.1. Per evitare problemi durante l'aggiornamento, puoi utilizzare .
Perché non abbiamo avuto tali problemi su dev? Il database viene copiato periodicamente da production — in questo modo, le tabelle vengono ricreate.
Sfortunatamente, su un grande database operativo non è possibile semplicemente eseguire un'operazione di Se nella partizione è rimasto solo un pezzo, non si può avviare la fusione con il comando normale, è necessario utilizzare. Qui aiuta percona-toolkit: per l'operazione online OPTIMIZE, l'utility pt-online-schema-change è perfetta.
Il piano aggiornato è diventato il seguente:
- Effettuare l'ottimizzazione di tutte le tabelle.
- Aggiornare i database.
Per verificarlo e 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 blocchi prolungati grazie al fatto che l'utilità 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 ci vorrebbero circa 24 ore, ma nel frattempo la copia dei dati ha causato un carico eccessivo sui dischi.
Per evitare ciò, in produzione abbiamo aggiunto un argomento al comando --sleep con un valore di 10: questo parametro regola la durata dell'attesa dopo che un gruppo di dati è stato trasferito nella nuova tabella. In questo modo si può ridurre il carico, se l'applicazione effettivamente in esecuzione è esigente in termini di tempi di risposta.
Dopo l'ottimizzazione, l'aggiornamento è andato a buon fine.
… ma non del tutto!
Già dopo mezz'ora dall'aggiornamento, un cliente è venuto con un problema. Il database funzionava in modo molto strano: a intervalli si verificavano reset delle connessioni. Ecco come si presentava nel monitoraggio:

Nello screenshot si vede un grafico a forma di sega, legato al fatto che alcuni thread del server MySQL si interrompevano periodicamente con un errore. Nell'applicazione sono apparsi degli errori:
[PDOException] SQLSTATE[HY000] [2002] Connection refusedUna rapida revisione dei log ha rivelato che il demone mysqld non riusciva a ottenere le risorse richieste dal sistema operativo. Esaminando gli errori, abbiamo scoperto nel sistema file di policy di 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 erano stati creati durante l'aggiornamento a MySQL 5.7 un paio di anni fa e appartenevano a un pacchetto rimosso. La loro rimozione 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 studiato non garantisce sempre il risultato atteso. Ora, in qualsiasi piano di aggiornamento, il nostro team include anche la pulizia obbligatoria dei file inutili che potrebbero essere apparsi a causa delle azioni recenti.
Con quest'opera grafica non molto professionale vorrei dire un enorme grazie a Percona per i loro ottimi prodotti!

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