MySQL 8.0 ha apportato enormi cambiamenti e modifiche che sono stati promossi dall'Oracle MySQL Team. I file fisici sono stati modificati. Ad esempio, *.frm, *.TRG, *.TRN e *.par non esistono più. Sono state aggiunte tonnellate di nuove funzionalità come CTE (Common Table Expressions), Window Functions, Invisible Indexes, regexp (o Regular Expression):quest'ultima è stata modificata e ora fornisce il pieno supporto Unicode ed è multibyte sicuro. Anche il dizionario dei dati è cambiato. Ora è incorporato in un dizionario di dati transazionali che memorizza le informazioni sugli oggetti del database. A differenza delle versioni precedenti, i dati del dizionario venivano archiviati in file di metadati e tabelle non transazionali. La sicurezza è stata migliorata con la nuova aggiunta di caching_sha2_password, che ora è l'autenticazione predefinita che sostituisce mysql_native_password e offre maggiore flessibilità ma sicurezza rafforzata che deve utilizzare una connessione sicura o una connessione non crittografata che supporta lo scambio di password utilizzando una coppia di chiavi RSA.
Con tutte queste fantastiche funzionalità, miglioramenti e miglioramenti offerti da MySQL 8.0, il nostro team era interessato a determinare le prestazioni della versione corrente di MySQL 8.0, soprattutto dato che il nostro supporto per le versioni di MySQL 8.0.x in ClusterControl è in arrivo (quindi rimanete sintonizzati su questo). Questo post del blog non discuterà le funzionalità di MySQL 8.0, ma intende confrontare le sue prestazioni con MySQL 5.7 e vedere come è migliorato allora.
Configurazione del server e ambiente
Per questo benchmark, intendo utilizzare una configurazione minima per la produzione utilizzando il seguente ambiente AWS EC2:
Tipo di istanza:istanza t2.xlarge
Archiviazione:gp2 (archiviazione SSD con minimo 100 e massimo 16000 IOPS)
vCPUS:4
Memoria:16GiB
Versione MySQL 5.7:MySQL Community Server (GPL) 5.7.24
Versione MySQL 8.0:MySQL Community Server - GPL 8.0.14
Ci sono alcune variabili degne di nota che ho impostato anche per questo benchmark, che sono:
- innodb_max_dirty_pages_pct =90 ## Questo è il valore predefinito in MySQL 8.0. Vedi qui per i dettagli.
- innodb_max_dirty_pages_pct_lwm=10 ## Questo è il valore predefinito in MySQL 8.0
- innodb_flush_neighbors=0
- innodb_buffer_pool_instances=8
- innodb_buffer_pool_size=8GiB
Il resto delle variabili impostate qui per entrambe le versioni (MySQL 5.7 e MySQL 8.0) sono già ottimizzate da ClusterControl per il suo modello my.cnf.
Inoltre, l'utente che ho usato qui non è conforme alla nuova autenticazione di MySQL 8.0 che utilizza caching_sha2_password. Invece, entrambe le versioni del server utilizzano mysql_native_password più la variabile innodb_dedicated_server è OFF (impostazione predefinita), che è una nuova funzionalità di MySQL 8.0.
Per semplificare la vita, ho configurato il nodo della versione Community di MySQL 5.7 con ClusterControl da un host separato, quindi ho rimosso il nodo in un cluster e ho spento l'host ClusterControl per rendere dormiente il nodo MySQL 5.7 (nessun traffico di monitoraggio). Tecnicamente, entrambi i nodi MySQL 5.7 e MySQL 8.0 sono dormienti e nessuna connessione attiva passa attraverso i nodi, quindi è essenzialmente un puro test di benchmarking.
Comandi e script utilizzati
Per questa attività, sysbench viene utilizzato per il test e la simulazione del carico per i due ambienti. Di seguito sono riportati i seguenti comandi o script utilizzati in questo test:
sb-prepare.sh
#!/bin/bash
host=$1
#host192.168.10.110
port=3306
user='sysbench'
password='[email protected]'
table_size=500000
rate=20
ps_mode='disable'
sysbench /usr/share/sysbench/oltp_read_write.lua --db-driver=mysql --threads=1 --max-requests=0 --time=3600 --mysql-host=$host --mysql-user=$user --mysql-password=$password --mysql-port=$port --tables=10 --report-interval=1 --skip-trx=on --table-size=$table_size --rate=$rate --db-ps-mode=$ps_mode prepare
sb-run.sh
#!/usr/bin/env bash
host=$1
port=3306
user="sysbench"
password="[email protected]"
table_size=100000
tables=10
rate=20
ps_mode='disable'
threads=1
events=0
time=5
trx=100
path=$PWD
counter=1
echo "thread,cpu" > ${host}-cpu.csv
for i in 16 32 64 128 256 512 1024 2048;
do
threads=$i
mysql -h $host -e "SHOW GLOBAL STATUS" >> $host-global-status.log
tmpfile=$path/${host}-tmp${threads}
touch $tmpfile
/bin/bash cpu-checker.sh $tmpfile $host $threads &
/usr/share/sysbench/oltp_read_write.lua --db-driver=mysql --events=$events --threads=$threads --time=$time --mysql-host=$host --mysql-user=$user --mysql-password=$password --mysql-port=$port --report-interval=1 --skip-trx=on --tables=$tables --table-size=$table_size --rate=$rate --delete_inserts=$trx --order_ranges=$trx --range_selects=on --range-size=$trx --simple_ranges=$trx --db-ps-mode=$ps_mode --mysql-ignore-errors=all run | tee -a $host-sysbench.log
echo "${i},"`cat ${tmpfile} | sort -nr | head -1` >> ${host}-cpu.csv
unlink ${tmpfile}
mysql -h $host -e "SHOW GLOBAL STATUS" >> $host-global-status.log
done
python $path/innodb-ops-parser.py $host
mysql -h $host -e "SHOW GLOBAL VARIABLES" >> $host-global-vars.log
Quindi lo script prepara semplicemente lo schema sbtest e popola tabelle e record. Quindi esegue test di carico in lettura/scrittura utilizzando lo script /usr/share/sysbench/oltp_read_write.lua. Lo script esegue il dump dello stato globale e delle variabili MySQL, raccoglie l'utilizzo della CPU e analizza le operazioni sulle righe InnoDB gestite dallo script innodb-ops-parser.py. Gli script quindi generano file *.csv in base ai registri scaricati che sono stati raccolti durante il benchmark, quindi ho utilizzato un foglio di calcolo Excel qui per generare il grafico dai file *.csv. Si prega di controllare il codice qui in questo repository github.
Ora procediamo con i risultati del grafico!
Operazioni su riga InnoDB
Fondamentalmente qui, ho estratto solo le operazioni sulla riga di InnoDB che seleziona (legge), elimina, inserisce e aggiorna. Quando il numero di thread aumenta, MySQL 8.0 supera in modo significativo MySQL 5.7! Entrambe le versioni non hanno modifiche specifiche alla configurazione, ma solo le variabili importanti che ho impostato. Quindi entrambe le versioni utilizzano praticamente i valori predefiniti.
È interessante notare che, per quanto riguarda le affermazioni del team di MySQL Server sulle prestazioni di lettura e scrittura nella nuova versione, i grafici indicano un significativo miglioramento delle prestazioni, specialmente in un server ad alto carico. Immagina la differenza tra MySQL 5.7 e MySQL 8.0 per tutte le sue operazioni di riga InnoDB, c'è un'elevata differenza soprattutto quando il numero di thread aumenta. MySQL 8.0 rivela che può funzionare in modo efficiente indipendentemente dal suo carico di lavoro.
Transazioni elaborate
Come mostrato nel grafico sopra, le prestazioni di MySQL 8.0 mostrano ancora un'enorme differenza nel tempo necessario per elaborare le transazioni. Più è basso, migliori sono le prestazioni, il che significa che è più veloce elaborare le transazioni. Le transazioni elaborate (il secondo grafico) rivelano inoltre che entrambi i numeri di transazioni non differiscono l'uno dall'altro. Ciò significa che entrambe le versioni eseguono quasi lo stesso numero di transazioni ma differiscono per la velocità con cui può finire. Anche se posso dire che MySQL 5.7 è ancora in grado di gestire molto con un carico inferiore, ma ci si potrebbe aspettare che il carico realistico, soprattutto in produzione, sia maggiore, specialmente nel periodo più intenso.
Il grafico sopra mostra ancora le transazioni che è stato in grado di elaborare ma separa la lettura dalle scritture. Tuttavia, ci sono in realtà valori anomali nei grafici che non ho incluso in quanto sono piccoli bocconcini del risultato che distorcerebbero il grafico.
MySQL 8.0 rivela grandi miglioramenti soprattutto per le letture. Mostra la sua efficienza nelle scritture soprattutto per i server con un carico di lavoro elevato. Un grande supporto aggiuntivo che influisce sulle prestazioni di MySQL per le letture nella versione 8.0 è la possibilità di creare un indice in ordine decrescente (o scansioni in avanti dell'indice). Le versioni precedenti avevano solo una scansione dell'indice ascendente o all'indietro e MySQL doveva eseguire filesort se aveva bisogno di un ordine decrescente (se è necessario filesort, potresti considerare di controllare il valore di max_length_for_sort_data). Gli indici decrescenti consentono inoltre all'ottimizzatore di utilizzare indici a più colonne quando l'ordine di scansione più efficiente combina l'ordine crescente per alcune colonne e l'ordine decrescente per altre. Vedi qui per maggiori dettagli.
Risorse CPU
Durante questo benchmarking, ho deciso di prendere alcune risorse hardware, in particolare l'utilizzo della CPU.
Lascia che ti spieghi prima come prendo qui la risorsa CPU durante il benchmarking. sysbench non include statistiche collettive per le risorse hardware utilizzate o utilizzate durante il processo durante il benchmarking di un database. Per questo motivo, quello che ho fatto è creare un flag creando un file, connettermi all'host di destinazione tramite SSH, quindi raccogliere i dati dal comando Linux "top" e analizzarli mentre dormivo per un secondo prima di raccoglierli di nuovo. Successivamente, prendi l'aumento più notevole dell'utilizzo della CPU per il processo mysqld e quindi rimuovi il file flag. Puoi rivedere il codice che ho in github.
Quindi discutiamo di nuovo del risultato del grafico, sembra rivelare che MySQL 8.0 consuma molta CPU. Più di MySQL 5.7. Tuttavia, potrebbe avere a che fare con nuove variabili aggiunte in MySQL 8.0. Ad esempio, queste variabili potrebbero influire sul tuo server MySQL 8.0:
- innodb_log_spin_cpu_abs_lwm =80
- innodb_log_spin_cpu_pct_hwm =50
- innodb_log_wait_for_flush_spin_hwm =400
- innodb_parallel_read_threads =4
Le variabili con i suoi valori vengono lasciate dai valori predefiniti per questo benchmark. Le prime tre variabili gestiscono la CPU per il redo logging, che in MySQL 8.0 è stato un miglioramento dovuto alla riprogettazione del modo in cui InnoDB scrive nel registro REDO. La variabile innodb_log_spin_cpu_pct_hwm ha affinità con la CPU, il che significa che ignorerebbe altri core della CPU se mysqld è bloccato solo su 4 core, ad esempio. Per i thread di lettura parallela, in MySQL 8.0, aggiunge una nuova variabile per la quale puoi regolare quanti thread utilizzare.
Tuttavia, non ho approfondito ulteriormente l'argomento. Ci possono essere modi per migliorare le prestazioni sfruttando le funzionalità che MySQL 8.0 ha da offrire.
Conclusione
Ci sono tonnellate di miglioramenti presenti in MySQL 8.0. I risultati del benchmark rivelano che c'è stato un notevole miglioramento, non solo nella gestione dei carichi di lavoro di lettura, ma anche su un carico di lavoro di lettura/scrittura elevato rispetto a MySQL 5.7.
Passando alle nuove funzionalità di MySQL 8.0, sembra che abbia sfruttato le tecnologie più aggiornate non solo sul software (come il grande miglioramento per Memcached, la gestione remota per un migliore lavoro DevOps, ecc.) ma anche nell'hardware. Ad esempio, la sostituzione di latin1 con UTF8MB4 come codifica dei caratteri predefinita. Ciò significherebbe che richiederebbe più spazio su disco poiché UTF8 richiede 2 byte sui caratteri non ASCII statunitensi. Sebbene questo benchmark non abbia sfruttato l'utilizzo del nuovo metodo di autenticazione con caching_sha2_password, non influirà sulle prestazioni se utilizza la crittografia. Una volta autenticato, viene archiviato nella cache, il che significa che l'autenticazione viene eseguita solo una volta. Quindi, se stai utilizzando un utente per il tuo client, non sarà un problema ed è più sicuro rispetto alle versioni precedenti.
Poiché MySQL sfrutta l'hardware e il software più aggiornati, cambia le sue variabili predefinite. Puoi leggere qui per maggiori dettagli.
Nel complesso, MySQL 8.0 ha dominato MySQL 5.7 in modo efficiente.