
Pokrok se zastavit nedá, a proto se důvody pro přechod na aktuální verze MySQL stávají stále závažnějšími. Nedávno v jednom z našich projektů nastal čas aktualizovat pohodlné clustery Percona Server 5.7 na 8. verzi. To vše probíhalo na platformě Ubuntu Linux 16.04. Jak provést takovou operaci s minimálním výpadkem a s jakými problémy jsme se setkali během aktualizace — čtěte v tomto článku.
Příprava
Jakákoliv aktualizace serveru databází je pravděpodobně spojena s přenastavením databáze: změnou požadavků na limity systémových zdrojů a úpravou konfiguračních souborů databáze, které je potřeba vyčistit od zastaralých direktiv.
Před aktualizací se určitě obrátíme na oficiální dokumentaci:
- ;
- ;
- ;
- .
A sestavíme plán akcí:
- Opravit konfigurační soubory, odstranit zastaralé direktivy.
- Zkontrolovat kompatibilitu nástroji.
- Aktualizovat slave databáze, nainstalovat balíček
percona-server-server. - Aktualizovat master, nainstalovat stejný balíček.
Rozebere každý bod plánu a podíváme se, co všechno může jít špatně.
DŮLEŽITÉ! Procedura aktualizace MySQL clusteru na bázi Galera má své nuance, které nejsou v článku popsány. Není dobré tuto instrukci používat v takovém případě.
Část 1: Kontrola konfigurací
V 8. verzi MySQL byla odstraněna query_cache. Vlastně byla už ve verzi 5.7, ale nyní je . Proto je nutné odstranit související direktivy. A pro cacheování dotazů lze nyní použít externí nástroje — například, .
Také v konfiguraci se našly zastaralé direktivy o innodb_file_format. Pokud ve MySQL 5.7 byla možnost volby formátu InnoDB, 8. verze již funguje .
Naším výsledkem je odstranění následujících direktiv:
-
query_cache_type,query_cache_limitaquery_cache_size; -
innodb_file_formatainnodb_file_format_max.
Pro kontrolu využijeme Docker obraz Percona Server. Konfiguraci serveru umístíme do adresáře mysql_config_test, a vedle vytvoříme adresáře pro data a logy. Příklad testování konfigurace 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-centosVýsledek: buď v logách Dockeru, nebo v adresáři s logy – v závislosti na vašich konfiguracích – se objeví soubor, ve kterém budou popsány problematické direktivy.
Toto jsme měli my:
2020-04-03T12:44:19.670831Z 0 [Warning] [MY-011068] [Server] Syntaxe 'expire-logs-days' je zastaralá a bude odstraněna v budoucích verzích. Místo toho použijte binlog_expire_logs_seconds.
2020-04-03T12:44:19.671678Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' je v současnosti aliasem pro znakovou sadu UTF8MB3, ale bude v budoucnu aliasem pro UTF8MB4. Zvažte použití UTF8MB4 pro jednoznačnost.
2020-04-03T12:44:19.671682Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' je kolace zastaralé znakově sady UTF8MB3. Zvažte použití UTF8MB4 s vhodnou kolací místo toho. Takže jsme se museli ještě vyrovnat s kódováním a nahradit zastaralou direktivu expire-logs-days.
Část 2: Kontrola funkčních instalací
V dokumentaci k aktualizaci jsou 2 utilitky pro kontrolu databáze na kompatibilitu. Jejich použití pomáhá administrátorům ověřit kompatibilitu stávající struktury dat.
Začneme s klasikou, utilitou mysqlcheck. Stačí ji pouze spustit:
mysqlcheck -u root -p --all-databases --check-upgradePokud nejsou zjištěny žádné problémy, utilita se ukončí s kódem 0:

Kromě toho jsou v moderních verzích MySQL k dispozici utilita (v případě Percony jde o balíček percona-mysql-shell). Je to náhrada za klasického klienta mysql a kombinuje funkce klienta, editoru SQL kódu a nástroje pro správu MySQL. Pro kontrolu serveru před aktualizací lze přes ni provést následující příkaz:
mysqlsh -- util check-for-server-upgrade { --user=root --host=1.1.1.1 --port=3306 } --config-path=\/etc\/mysql\/my.cnfA tady jsou poznámky, které jsme obdrželi:

Celkově nic kritického – pouze varování o kódování (viz níže). Celkový výsledek byl:

Rozhodli jsme se, že aktualizace by měla proběhnout bez problémů.
Poznámka k varováním výše, naznačujícím problémy s kódováním. Skutečností je, že UTF-8 v MySQL do nedávna , protože uchovávala pouze 3 bajty místo 4. V MySQL 8 se to konečně : alias utf8 brzy povede na kódování utf8mb4, zatímco staré sloupce v tabulkách se stanou utf8mb3. V budoucnu bude toto kódování odstraněno, ale ne v této verzi. Proto jsme se rozhodli provést opravu kódování již na provozní instalaci DBMS po její aktualizaci. utf8mb3 Část 3: Aktualizace serverů
Část 3: Aktualizace serverů
Co se může pokazit, když máme tak skvělý plán?.. Plně si uvědomujeme, že detaily se vždy mohou objevit, první experiment jsme provedli na dev-klastru MySQL.
Jak již bylo zmíněno, se zabývá otázkou aktualizace MySQL serverů s replikami. Podstatou je, že nejprve by měly být aktualizovány všechny repliky (slave), protože MySQL 8 umí replikovat z mastera verze 5.7. Určitá složitost spočívá v tom, že používáme režim master master, kdy vzdálený master je v režimu read-only. To znamená, že skutečný provoz směřuje do jednoho datacentra, zatímco druhé slouží jako záložní.
Topologie vypadá následovně:

Aktualizace by měla začít s replikami mysql replica dc 2, mysql master dc 2 a mysql replica dc 1, a skončit — serverem mysql master dc 1. Pro větší spolehlivost jsme zastavili virtuální stroje, vytvořili jejich snapshoty a přímo před aktualizací zastavili replikaci příkazem STOP SLAVE. Jinak vypadá aktualizace následovně:
- Každou replikaci restartujeme s přidáním 3 voleb do konfigurací:
skip-networking,skip-slave-start,skip-log-bin. Je to proto, že aktualizace databáze generuje binární logy s aktualizací systémových tabulek. Tyto direktivy zaručují, že v databázi nedojde k změně údajů aplikace a do binárních logů se nedostanou informace o aktualizaci systémových tabulek. To pomůže předejít problémům při obnovení replikace. - Nainstalujeme balíček
percona-server-server. Je důležité poznamenat, že ve verzi MySQL 8 ne je nutné spustit příkazmysqlupgradepo aktualizaci serveru. - Po úspěšném spuštění server znovu restartujeme — již bez parametrů, které byly přidány v prvním bodě.
- Ujistíme se, že replikace úspěšně funguje: zkontrolujeme
SHOW SLAVE STATUSa sledujeme, že se tabulky sečítají v databázi aplikace.
Vše to vypadá docela jednoduše: aktualizace dev proběhla úspěšně. Dobře, můžeme klidně naplánovat noční aktualizaci pro production.
Žádné starosti — prod jsme aktualizovali
Avšak přenos úspěšných zkušeností z dev do production se neobešel bez překvapení.
Naštěstí samotný proces aktualizace začíná s replikami, takže pokud narazíme na potíže, zastavili jsme práce a obnovili replikaci ze snapshotu. Prozkoumání problémů jsme odložili na následující ráno. V logách jsme nalezli následující záznamy:
2020-01-14T21:43:21.500563Z 2 [ERROR] [MY-012069] [InnoDB] tabulka: t1 má 19 sloupců, ale slovník InnoDB má 20 sloupců
2020-01-14T21:43:21.500722Z 2 [ERROR] [MY-010767] [Server] Chyba při opravě dat SE pro db1.t1
2020-01-14T21:43:24.208365Z 0 [ERROR] [MY-010022] [Server] Nepodařilo se naplnit tabulky DD.
2020-01-14T21:43:24.208658Z 0 [ERROR] [MY-010119] [Server] Zrušeno Zkoumání archivů různých emailových kampaní v Googlu vedlo k pochopení, že tento problém vzniká kvůli . Ačkoli je to spíše bug nástrojů mysqlcheck a mysqlsh.
Odkazuje se na to, že MySQL změnilo způsob prezentace dat pro desítková pole (int, tinyint atd.), a proto se uvnitř mysql-server používá jiný způsob jejich ukládání. Pokud vaše databáze původně byla ve verzi 5.5 nebo 5.1 a následně jste se aktualizovali na 5.7, možná je třeba provést OPTIMIZE pro některé tabulky. Poté MySQL aktualizuje soubory s daty a převede je na aktuální formát ukládání.
Toto lze také zkontrolovat nástrojem mysqlfrm:
mysqlfrm --diagnostic -vv /var/lib/mysql/db/table.frm
...
'field_length': 8,
'field_type': 246, # formát pole
'field_type_name': 'decimal',
'flags': 3,
'flags_extra': 67,
'interval_nr': 0,
'name': 'your_decimal_column',
... Pokud field_type u vás je 0, pak se v tabulce používá starý typ — je nutné provést OPTIMIZE. Nicméně, pokud je hodnota 246 — máte již nový typ. Podrobnosti o typech lze nalézt v .
Navíc, v se zvažuje druhá možná příčina, která nás minula — absence tabulek InnoDB v systémové tabulce INNODB_SYS_TABLESPACES, pokud byly tabulky vytvořeny ve verzi 5.1. Aby se předešlo problémům při aktualizaci, můžete využít .
Proč se nám na dev nevyskytly takové problémy? Databáze se tam periodicky kopíruje z produkce — tímto způsobem tabulky se znovu vytvářejí.
Bohužel, na skutečné velké DB nebude možné jednoduše vzít a provést hromadné OPTIMIZE. Zde pomůže percona-toolkit: pro operaci online OPTIMIZE se skvěle hodí nástroj pt-online-schema-change.
Aktualizovaný plán se nyní stal následujícím:
- Provést optimalizaci všech tabulek.
- Provést aktualizaci databází.
Abychom ho ověřili a zároveň zjistili čas aktualizace, odpojili jsme jednu z replik a pro všechny tabulky spustili následující příkaz:
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=t1Aktualizace tabulek se provádí bez dlouhých blokací, protože nástroj vytváří novou dočasnou tabulku, do které kopíruje data z hlavní tabulky. V okamžiku, kdy jsou obě tabulky identické, je hlavní tabulka zablokována a nahrazena novou. V našem případě testovací spuštění ukázalo, že pro aktualizaci všech tabulek bude potřeba přibližně jeden den, ale kopírování dat vyvolávalo příliš velkou zátěž na disky.
Abychom tomu předešli, na produkci jsme přidali k příkazu argument --sleep s hodnotou 10 — tento parametr reguluje délku čekání po přesunu dávky dat do nové tabulky. Tím lze snížit zátěž, pokud je skutečně spuštěná aplikace citlivá na časovou odezvu.
Po provedení optimalizace proběhla aktualizace úspěšně.
… ale ne do konce!
Už po půl hodině od aktualizace klient přišel s problémem. Databáze fungovala velmi podivně: občas se začaly resetování připojení. Takto to vypadalo v monitorování:

Na snímku obrazovky je vidět zubatá křivka, související s tím, že část vláken MySQL serveru občas selhávala s chybou. V aplikaci se objevily chyby:
[PDOException] SQLSTATE[HY000] [2002] Připojení bylo odmítnutoRychlý pohled do logů odhalil, že démon mysqld nemohl získat požadované zdroje od operačního systému. Při zkoumání chyb jsme v systému objevili "opuštěné" soubory politik 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 amd64Tyto soubory vznikly při aktualizaci na MySQL 5.7 před pár lety a patří vzdálenému balíčku. Smazání souborů a restart služby apparmor problém vyřešilo:
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 apparmorNa závěr
Jakákoli, i ta nejjednodušší operace, může vést k neočekávaným problémům. A dokonce i existence promyšleného plánu nezaručuje vždy očekávaný výsledek. Nyní do jakýchkoli plánů aktualizace našeho týmu zahrnuje také povinné vyčištění zbytečných souborů, které mohly vzniknout v důsledku posledních akcí.
A tímto ne příliš profesionálním grafickým výtvorům bych chtěl říci obrovské díky společnosti Percona za jejich vynikající produkty!

P.S.
Přečtěte si také náš blog:
- «»;
- «»;
- «»;
- «»;
- «».
Zdroj: habr.com
