Aktualizacja MySQL (serwer Percona) z wersji 5.7 do 8.0

Aktualizacja MySQL (serwer Percona) z wersji 5.7 do 8.0

Postęp nie stoi w miejscu, więc powody, dla których warto uaktualnić MySQL do najnowszej wersji, stają się coraz bardziej przekonujące. Nie tak dawno temu w jednym z naszych projektów przyszedł czas na aktualizację przytulnych klastrów Percona Server 5.7 do wersji 8. Wszystko to wydarzyło się na platformie Ubuntu Linux 16.04. Jak wykonać taką operację przy minimalnym przestoju i jakie problemy napotkaliśmy podczas aktualizacji - przeczytaj w tym artykule.

Szkolenie

Jakakolwiek aktualizacja serwera bazy danych wiąże się najprawdopodobniej z rekonfiguracją bazy danych: zmianami wymagań dotyczących limitów zasobów systemowych i korektą konfiguracji baz danych, które wymagają oczyszczenia z nieaktualnych dyrektyw.

Przed aktualizacją na pewno odniesiemy się do oficjalnej dokumentacji:

I opracujmy plan działania:

  1. Popraw pliki konfiguracyjne, usuwając przestarzałe dyrektywy.
  2. Sprawdź zgodność z narzędziami.
  3. Zaktualizuj podrzędne bazy danych, instalując pakiet percona-server-server.
  4. Zaktualizuj mastera za pomocą tego samego pakietu.

Przyjrzyjmy się każdemu punktowi planu i zobaczmy, co może pójść nie tak.

WAŻNE! Procedura aktualizacji klastra MySQL opartego na Galerze ma swoje subtelności, które nie są opisane w artykule. W tym przypadku nie powinieneś używać tej instrukcji.

Część 1: Sprawdzanie konfiguracji

MySQL został usunięty w wersji 8 query_cache. Właściwie był uznany za przestarzały z powrotem w wersji 5.7, ale teraz całkowicie usunięte. W związku z tym konieczne jest usunięcie powiązanych dyrektyw. A do buforowania żądań możesz teraz używać narzędzi zewnętrznych - na przykład ProxySQL.

Również w konfiguracji były przestarzałe dyrektywy dotyczące innodb_file_format. Jeśli w MySQL 5.7 można było wybrać format InnoDB, to 8. wersja już działa tylko w formacie Barracuda.

Naszym efektem jest usunięcie następujących dyrektyw:

  • query_cache_type, query_cache_limit и query_cache_size;
  • innodb_file_format и innodb_file_format_max.

Aby to sprawdzić, użyjemy obrazu Dockera serwera Percona. Umieścimy konfigurację serwera w katalogu mysql_config_test, a obok niego utworzymy katalogi na dane i logi. Przykład testu konfiguracji serwera Percona:

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-centos

Konkluzja: albo w logach Dockera, albo w katalogu z logami - w zależności od twoich konfiguracji - pojawi się plik, w którym zostaną opisane problematyczne dyrektywy.

Oto co mieliśmy:

2020-04-03T12:44:19.670831Z 0 [Warning] [MY-011068] [Server] The syntax 'expire-logs-days' is deprecated and will be removed in a future release. Please use binlog_expire_logs_seconds instead.
2020-04-03T12:44:19.671678Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.
2020-04-03T12:44:19.671682Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' is a collation of the deprecated character set UTF8MB3. Please consider using UTF8MB4 with an appropriate collation instead.

Dlatego nadal musieliśmy wymyślić kodowanie i zastąpić przestarzałą dyrektywę expire-logs-days.

Część 2: Sprawdzenie działających instalacji

Dokumentacja aktualizacji zawiera 2 narzędzia do sprawdzania bazy danych pod kątem kompatybilności. Ich użycie pomaga administratorowi sprawdzić zgodność istniejącej struktury danych.

Zacznijmy od klasycznego narzędzia mysqlcheck. Po prostu uruchom:

mysqlcheck -u root -p --all-databases --check-upgrade

Jeśli nie zostaną znalezione żadne problemy, narzędzie zakończy działanie z kodem 0:

Aktualizacja MySQL (serwer Percona) z wersji 5.7 do 8.0

Ponadto narzędzie jest dostępne w nowoczesnych wersjach MySQL powłoka mysql (w przypadku Percony jest to pakiet percona-mysql-shell). Jest zamiennikiem klasycznego klienta mysql i łączy w sobie funkcje klienta, edytora kodu SQL i narzędzi administracyjnych MySQL. Aby sprawdzić serwer przed aktualizacją, możesz uruchomić za jego pośrednictwem następujące polecenia:

mysqlsh -- util check-for-server-upgrade { --user=root --host=1.1.1.1 --port=3306 } --config-path=/etc/mysql/my.cnf

Oto komentarze, które otrzymaliśmy:

Aktualizacja MySQL (serwer Percona) z wersji 5.7 do 8.0

Generalnie nic krytycznego - jedynie ostrzeżenia o kodowaniu (patrz poniżej). Ogólny wynik wykonania:

Aktualizacja MySQL (serwer Percona) z wersji 5.7 do 8.0

Uznaliśmy, że aktualizacja powinna przejść bez problemów.

Uwaga dotycząca powyższych ostrzeżeń wskazujących problemy z kodowaniem. Faktem jest, że do niedawna UTF-8 w MySQL nie był „prawdziwym” kodem UTF-8, ponieważ zapisał tylko 3 bajty zamiast 4. W MySQL 8 tak jest w końcu zdecydowałem się to naprawić: Alias utf8 wkrótce doprowadzi do kodowania utf8mb4, a stare kolumny w tabelach staną się utf8mb3. Dalsze kodowanie utf8mb3 zostaną usunięte, ale nie w tej wersji. Dlatego postanowiliśmy poprawić kodowanie już w działającej instalacji DBMS, po jej aktualizacji.

Część 3: Aktualizacje serwera

Co może pójść nie tak, gdy istnieje tak mądry plan?.. Doskonale rozumiejąc, że niuanse zawsze się zdarzają, przeprowadziliśmy pierwszy eksperyment na klastrze deweloperskim MySQL.

Jak już wspomniano, oficjalna dokumentacja obejmuje problematykę aktualizacji serwerów MySQL za pomocą replik. Najważniejsze jest to, że powinieneś najpierw zaktualizować wszystkie repliki (slave), ponieważ MySQL 8 może replikować z wersji głównej 5.7. Pewna trudność polega na tym, że korzystamy z tego trybu mistrz <-> mistrz, gdy zdalny moduł nadrzędny jest w trybie tylko do odczytu. Oznacza to, że w rzeczywistości ruch bojowy trafia do jednego centrum danych, a drugie jest zapasowe.

Topologia wygląda następująco:

Aktualizacja MySQL (serwer Percona) z wersji 5.7 do 8.0

Aktualizację należy rozpocząć od replik replika mysql dc2, mysql master dc2 и mysql replica dc 1, a kończymy na serwerze mysql master dc 1. Aby być bardziej niezawodnym, zatrzymaliśmy maszyny wirtualne, zrobiliśmy ich migawki i tuż przed aktualizacją zatrzymaliśmy replikację poleceniem STOP SLAVE. Pozostała część aktualizacji wygląda następująco:

  1. Restartujemy każdą replikę dodając 3 opcje do konfiguracji: skip-networking, skip-slave-start, skip-log-bin. Faktem jest, że aktualizacja bazy danych generuje logi binarne z aktualizacjami tabel systemowych. Dyrektywy te gwarantują, że nie nastąpią żadne zmiany w danych aplikacji w bazie danych, a informacje o aktualizacji tabel systemowych nie będą uwzględniane w logach binarnych. Pozwoli to uniknąć problemów przy wznawianiu replikacji.
  2. Instalowanie pakietu percona-server-server. Należy zauważyć, że w wersji MySQL 8 nie musisz uruchomić polecenie mysqlupgrade po aktualizacji serwera.
  3. Po udanym starcie ponownie uruchamiamy serwer - bez parametrów, które zostały dodane w pierwszym akapicie.
  4. Dbamy o to, aby replikacja przebiegła pomyślnie: sprawdź SHOW SLAVE STATUS i sprawdź, czy tabele z licznikami w bazie danych aplikacji zostały zaktualizowane.

Wszystko wygląda dość prosto: aktualizacja deweloperska zakończyła się sukcesem. OK, możesz bezpiecznie zaplanować nocną aktualizację produkcyjną.

Nie było smutku - zaktualizowaliśmy prod

Jednak przeniesienie udanego doświadczenia deweloperskiego na produkcję nie obyło się bez niespodzianek.

Na szczęście sam proces aktualizacji rozpoczyna się od replik, więc gdy napotkaliśmy trudności, przerywaliśmy pracę i przywracaliśmy replikę z migawki. Badanie problemów odroczono do następnego ranka. W logach znajdowały się następujące wpisy:

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

Przeszukanie archiwów różnych list mailingowych w Google doprowadziło do zrozumienia, że ​​przyczyną tego problemu jest Błąd MySQL'a. Chociaż jest to bardziej prawdopodobny błąd narzędzia mysqlcheck и mysqlsh.

Okazuje się, że MySQL zmienił sposób, w jaki reprezentuje dane dla pól dziesiętnych (int, tinyint itp.), więc serwer mysql używa innego sposobu ich przechowywania. Jeśli Twoja baza danych początkowo był w wersji 5.5 lub 5.1, a następnie zaktualizowałeś do wersji 5.7, być może będziesz musiał to zrobić OPTIMIZE dla niektórych stołów. Następnie MySQL zaktualizuje pliki danych, przenosząc je do bieżącego formatu przechowywania.

Możesz to również sprawdzić za pomocą narzędzia mysqlfrm:

mysqlfrm --diagnostic -vv /var/lib/mysql/db/table.frm
...
 'field_length': 8,
  'field_type': 246, # формат поля
  'field_type_name': 'decimal',
  'flags': 3,
  'flags_extra': 67,
  'interval_nr': 0,
 'name': 'you_deciaml_column',
...

jeśli field_type Jeśli masz równy 0, w tabeli używany jest stary typ - musisz wykonać OPTIMIZE. Jeśli jednak wartość wynosi 246, masz już nowy typ. Więcej informacji na temat typów można znaleźć w kod.

Co więcej, w ten błąd Rozważamy drugi możliwy powód, który nas pominął: brak tabel InnoDB w tabeli systemowej INNODB_SYS_TABLESPACES, jeśli one, tabele, zostały utworzone w wersji 5.1. Aby uniknąć problemów podczas aktualizacji, możesz użyć załączony skrypt SQL.

Dlaczego nie mieliśmy takich problemów na wersji deweloperskiej? Baza danych jest tam okresowo kopiowana z produkcji - tym samym tabele są odtwarzane.

Niestety, w przypadku naprawdę działającej dużej bazy danych nie będzie można po prostu pobrać i wykonać uniwersalnej bazy danych OPTIMIZE. percona-toolkit będzie tutaj pomocny: narzędzie pt-online-schema-change doskonale nadaje się do operacji OPTYMALIZUJ online.

Zaktualizowany plan wyglądał tak:

  1. Zoptymalizuj wszystkie tabele.
  2. Zaktualizuj bazy danych.

Aby to sprawdzić i jednocześnie poznać czas aktualizacji, wyłączyliśmy jedną z replik i uruchomiliśmy dla wszystkich tabel następującą komendę:

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=t1

Tabele są aktualizowane bez długotrwałych blokad, ponieważ narzędzie tworzy nową tabelę tymczasową, do której kopiuje dane z tabeli głównej. W momencie, gdy obydwa stoły są identyczne, pierwotny stół zostaje zablokowany i zastąpiony nowym. W naszym przypadku uruchomienie testowe wykazało, że aktualizacja wszystkich tabel zajmie około jednego dnia, ale kopiowanie danych spowodowało zbyt duże obciążenie dysków.

Aby tego uniknąć, w środowisku produkcyjnym dodaliśmy argument do polecenia --sleep o wartości 10 - parametr ten reguluje długość oczekiwania po przesłaniu partii danych do nowej tabeli. W ten sposób można zmniejszyć obciążenie, jeśli aktualnie działająca aplikacja wymaga czasu reakcji.

Po przeprowadzeniu optymalizacji aktualizacja przebiegła pomyślnie.

... ale nie do końca!

W ciągu pół godziny po aktualizacji klient zgłosił się z problemem. Baza danych działała bardzo dziwnie: okresowo się uruchamiała połączenie zostanie zresetowane. Tak to wyglądało na monitoringu:

Aktualizacja MySQL (serwer Percona) z wersji 5.7 do 8.0

Zrzut ekranu przedstawia wykres piłokształtny wynikający z faktu, że niektóre wątki serwera MySQL okresowo ulegały awarii z powodu błędu. W aplikacji pojawiły się błędy:

[PDOException] SQLSTATE[HY000] [2002] Connection refused

Szybka inspekcja logów ujawniła, że ​​demon mysqld nie mógł uzyskać wymaganych zasobów z systemu operacyjnego. Podczas porządkowania błędów znaleźliśmy w systemie „sieroce” pliki zasad Apparmor:

# 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      amd64

Pliki te powstały podczas aktualizacji do MySQL 5.7 kilka lat temu i należą do usuniętego pakietu. Usunięcie plików i ponowne uruchomienie usługi apparmor rozwiązało problem:

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 apparmor

Na zakończenie

Każda, nawet najprostsza operacja może prowadzić do nieoczekiwanych problemów. A nawet posiadanie przemyślanego planu nie zawsze gwarantuje oczekiwany rezultat. Teraz wszelkie plany aktualizacji, które nasz zespół uwzględnia również obowiązkowe czyszczenie niepotrzebnych plików, które mogły pojawić się w wyniku ostatnich działań.

I przy okazji tej niezbyt profesjonalnej twórczości graficznej chciałbym bardzo podziękować firmie Percona za jej doskonałe produkty!

Aktualizacja MySQL (serwer Percona) z wersji 5.7 do 8.0

PS

Przeczytaj także na naszym blogu:

Źródło: www.habr.com

Dodaj komentarz