MySQL 8.0 przyniósł ogromne zmiany i modyfikacje, które zostały wprowadzone przez zespół Oracle MySQL. Zmieniono pliki fizyczne. Na przykład *.frm, *.TRG, *.TRN i *.par już nie istnieją. Dodano mnóstwo nowych funkcji, takich jak CTE (Common Table Expressions), Window Functions, Invisible Indexes, regexp (lub Regular Expression) — to ostatnie zostało zmienione i teraz zapewnia pełną obsługę Unicode i jest bezpieczne dla wielu bajtów. Zmienił się również słownik danych. Jest teraz zintegrowany ze słownikiem danych transakcyjnych, który przechowuje informacje o obiektach bazy danych. W przeciwieństwie do poprzednich wersji, dane słownikowe były przechowywane w plikach metadanych i tabelach nietransakcyjnych. Bezpieczeństwo zostało ulepszone dzięki nowemu dodaniu caching_sha2_password, które jest teraz domyślnym uwierzytelnianiem zastępującym mysql_native_password i oferuje większą elastyczność, ale zaostrzone zabezpieczenia, które muszą używać albo bezpiecznego połączenia, albo połączenia nieszyfrowanego, które obsługuje wymianę haseł za pomocą pary kluczy RSA.
Dzięki tym wszystkim fajnym funkcjom, ulepszeniom i ulepszeniom, które oferuje MySQL 8.0, nasz zespół był zainteresowany określeniem, jak dobrze działa bieżąca wersja MySQL 8.0, zwłaszcza biorąc pod uwagę, że nasza obsługa wersji MySQL 8.0.x w ClusterControl jest już w drodze (więc bądź na bieżąco na to). W tym poście na blogu nie będziemy omawiać funkcji MySQL 8.0, ale zamierzamy porównać jego wydajność z MySQL 5.7 i zobaczyć, jak się wtedy poprawiła.
Konfiguracja i środowisko serwera
W tym benchmarku zamierzam użyć minimalnej konfiguracji do produkcji przy użyciu następującego środowiska AWS EC2:
Typ instancji:t2.xlarge instance
Pamięć:gp2 (pamięć SSD z minimum 100 i maksimum 16000 IOPS)
vCPUS:4
Pamięć:16GiB
Wersja MySQL 5.7:MySQL Community Server (GPL) 5.7.24
Wersja MySQL 8.0:MySQL Community Server - GPL 8.0.14
Jest kilka godnych uwagi zmiennych, które ustawiłem również dla tego testu porównawczego, a mianowicie:
- innodb_max_dirty_pages_pct =90 ## Jest to wartość domyślna w MySQL 8.0. Zobacz tutaj, aby uzyskać szczegółowe informacje.
- innodb_max_dirty_pages_pct_lwm=10 ## To jest wartość domyślna w MySQL 8.0
- innodb_flush_neighbors=0
- innodb_buffer_pool_instances=8
- innodb_buffer_pool_size=8GiB
Pozostałe zmienne ustawione tutaj dla obu wersji (MySQL 5.7 i MySQL 8.0) są już dostrojone przez ClusterControl do szablonu my.cnf.
Ponadto użytkownik, którego tu użyłem, nie jest zgodny z nowym uwierzytelnianiem MySQL 8.0, które używa caching_sha2_password. Zamiast tego obie wersje serwera używają mysql_native_password, a zmienna innodb_dedicated_server jest wyłączona (domyślnie), co jest nową funkcją MySQL 8.0.
Aby ułatwić życie, konfiguruję węzeł MySQL 5.7 Community z ClusterControl z oddzielnego hosta, a następnie usuwam węzeł w klastrze i wyłączam hosta ClusterControl, aby węzeł MySQL 5.7 był uśpiony (brak ruchu monitorującego). Technicznie rzecz biorąc, oba węzły MySQL 5.7 i MySQL 8.0 są uśpione i żadne aktywne połączenia nie przechodzą przez węzły, więc jest to zasadniczo czysty test porównawczy.
Użyte polecenia i skrypty
Do tego zadania służy sysbench do testowania i symulacji obciążenia dla dwóch środowisk. Oto następujące polecenia lub skrypty używane w tym teście:
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
Więc skrypt po prostu przygotowuje schemat sbtest i wypełnia tabele i rekordy. Następnie wykonuje testy obciążenia odczytu/zapisu za pomocą skryptu /usr/share/sysbench/oltp_read_write.lua. Skrypt zrzuca globalny status i zmienne MySQL, zbiera wykorzystanie procesora i analizuje operacje wierszy InnoDB obsługiwane przez skrypt innodb-ops-parser.py. Skrypty następnie generują pliki *.csv na podstawie zrzuconych logów, które zostały zebrane podczas testu porównawczego, a następnie użyłem arkusza kalkulacyjnego Excela, aby wygenerować wykres z plików *.csv. Sprawdź kod tutaj w tym repozytorium github.
Teraz przejdźmy do wyników wykresu!
Operacje na wierszach InnoDB
Zasadniczo tutaj wyodrębniłem tylko operacje na wierszach InnoDB, które wybierają (odczytują), usuwają, wstawiają i aktualizują. Gdy liczba wątków rośnie, MySQL 8.0 znacznie przewyższa MySQL 5.7! Obie wersje nie mają żadnych konkretnych zmian w konfiguracji, a jedynie istotne zmienne, które ustawiłem. Więc obie wersje używają w zasadzie wartości domyślnych.
Co ciekawe, w odniesieniu do twierdzeń zespołu MySQL Server o wydajności odczytów i zapisów w nowej wersji, wykresy wskazują na znaczną poprawę wydajności, szczególnie w przypadku serwera o dużym obciążeniu. Wyobraź sobie różnicę między MySQL 5.7 a MySQL 8.0 dla wszystkich operacji na wierszach InnoDB. Różnica jest duża, szczególnie gdy liczba wątków rośnie. MySQL 8.0 pokazuje, że może działać wydajnie niezależnie od obciążenia.
Transakcje przetworzone
Jak pokazano na powyższym wykresie, wydajność MySQL 8.0 ponownie pokazuje ogromną różnicę w czasie przetwarzania transakcji. Im niższy, tym lepiej działa, co oznacza szybsze przetwarzanie transakcji. Przetworzone transakcje (drugi wykres) również pokazują, że obie liczby transakcji nie różnią się od siebie. Oznacza to, że obie wersje wykonują prawie taką samą liczbę transakcji, ale różnią się szybkością ich zakończenia. Chociaż mógłbym powiedzieć, że MySQL 5.7 nadal może obsłużyć wiele przy niższym obciążeniu, ale można oczekiwać, że realistyczne obciążenie, szczególnie w produkcji, będzie wyższe - zwłaszcza w najbardziej ruchliwym okresie.
Powyższy wykres nadal pokazuje transakcje, które był w stanie przetworzyć, ale oddziela odczyt od zapisów. Jednak na wykresach są wartości odstające, których nie uwzględniłem, ponieważ są to małe ciekawostki wyniku, które przekrzywiłyby wykres.
MySQL 8.0 ujawnia świetne ulepszenia, szczególnie w przypadku wykonywania odczytów. Wykazuje swoją wydajność w zapisach, szczególnie dla serwerów o dużym obciążeniu. Wspaniałym dodatkowym wsparciem, które wpływa na wydajność MySQL dla odczytów w wersji 8.0 jest możliwość tworzenia indeksu w kolejności malejącej (lub skanowania indeksu do przodu). Poprzednie wersje miały tylko skanowanie indeksu rosnącego lub wstecznego, a MySQL musiał wykonywać sortowanie plików, jeśli wymagało kolejności malejącej (jeśli sortowanie plików jest potrzebne, można rozważyć sprawdzenie wartości max_length_for_sort_data). Indeksy malejące umożliwiają również optymalizatorowi użycie indeksów wielokolumnowych, gdy najbardziej wydajna kolejność skanowania łączy kolejność rosnącą dla niektórych kolumn i kolejność malejącą dla innych. Więcej informacji znajdziesz tutaj.
Zasoby procesora
Podczas tego testu porównawczego zdecydowałem się wykorzystać niektóre zasoby sprzętowe, w szczególności wykorzystanie procesora.
Pozwólcie, że najpierw wyjaśnię, w jaki sposób pobieram tutaj zasoby procesora podczas testów porównawczych. sysbench nie obejmuje zbiorczych statystyk dotyczących zasobów sprzętowych wykorzystywanych lub wykorzystywanych podczas procesu testowania bazy danych. Z tego powodu stworzyłem flagę, tworząc plik, połączyłem się z docelowym hostem przez SSH, a następnie zebrałem dane z polecenia „top” Linuksa i przeanalizowałem je podczas snu przez sekundę przed ponownym zebraniem. Następnie weź najbardziej znaczący wzrost użycia procesora dla procesu mysqld, a następnie usuń plik flagi. Możesz przejrzeć kod, który mam na github.
Porozmawiajmy więc ponownie o wyniku wykresu, wydaje się, że pokazuje on, że MySQL 8.0 zużywa dużo procesora. Więcej niż MySQL 5.7. Jednak może mieć do czynienia z nowymi zmiennymi dodanymi w MySQL 8.0. Na przykład te zmienne mogą mieć wpływ na serwer 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
Zmienne z ich wartościami są pozostawione przez wartości domyślne dla tego testu porównawczego. Pierwsze trzy zmienne obsługują procesor w celu ponownego rejestrowania, co w MySQL 8.0 zostało ulepszone ze względu na przeprojektowanie sposobu, w jaki InnoDB zapisuje dziennik REDO. Zmienna innodb_log_spin_cpu_pct_hwm ma koligację procesora, co oznacza, że zignorowałaby inne rdzenie procesora, jeśli na przykład mysqld jest przypięty tylko do 4 rdzeni. W przypadku wątków odczytu równoległego w MySQL 8.0 dodaje nową zmienną, dla której można dostosować liczbę używanych wątków.
Nie zagłębiałem się jednak dalej w ten temat. Mogą istnieć sposoby na poprawę wydajności poprzez wykorzystanie funkcji oferowanych przez MySQL 8.0.
Wniosek
W MySQL 8.0 jest mnóstwo ulepszeń. Wyniki testu porównawczego pokazują, że nastąpiła imponująca poprawa, nie tylko w zarządzaniu obciążeniami odczytu, ale także w przypadku dużego obciążenia odczytu/zapisu w porównaniu z MySQL 5.7.
Przechodząc do nowych funkcji MySQL 8.0, wygląda na to, że wykorzystał on najnowocześniejsze technologie nie tylko w zakresie oprogramowania (takie jak doskonałe ulepszenie Memcached, zdalne zarządzanie dla lepszej pracy DevOps itp.), ale również w sprzęcie. Weźmy na przykład zamianę latin1 na UTF8MB4 jako domyślne kodowanie znaków. Oznaczałoby to, że wymagałoby to więcej miejsca na dysku, ponieważ UTF8 potrzebuje 2 bajtów na znaki spoza US-ASCII. Chociaż ten test porównawczy nie wykorzystał nowej metody uwierzytelniania z caching_sha2_password, nie wpłynie to na wydajność, jeśli używa szyfrowania. Po uwierzytelnieniu jest przechowywany w pamięci podręcznej, co oznacza, że uwierzytelnianie odbywa się tylko raz. Więc jeśli używasz jednego użytkownika dla swojego klienta, nie będzie to stanowiło problemu i jest bezpieczniejsze niż poprzednie wersje.
Ponieważ MySQL wykorzystuje najnowocześniejszy sprzęt i oprogramowanie, zmienia swoje domyślne zmienne. Możesz przeczytać tutaj, aby uzyskać więcej informacji.
Ogólnie rzecz biorąc, MySQL 8.0 skutecznie zdominował MySQL 5.7.