Актуализация на MySQL (Percona Server) от 5.7 до 8.0

Актуализация на MySQL (Percona Server) от 5.7 до 8.0

Напредъкът не спира, затова причините да се обновим до актуалните версии на MySQL стават все по-съществени. Съвсем наскоро в един от нашите проекти настъпи моментът за обновяване на удобните клъстери Percona Server 5.7 до версия 8. Всичко това се случва на платформата Ubuntu Linux 16.04. Как да извършим подобна операция с минимално време за престой и с какви проблеми се сблъскахме по време на обновлението — четете в тази статия.

Подготовка

Всяко обновление на сървър за бази данни вероятно е свързано с пренастройка на базата: промени в изискванията за лимити на системни ресурси и корекции на конфигурационните файлове, които трябва да бъдат почистени от остарели директиви.

Преди обновлението задължително ще се обърнем към официалната документация:

И ще съставим план за действие:

  1. Да коригираме конфигурационните файлове, като премахнем остарелите директиви.
  2. Да проверим съвместимостта с помощта на инструменти.
  3. Да обновим slave-базите, като инсталираме пакета percona-server-server.
  4. Да обновим мастера, като инсталираме същия пакет.

Ще разгледаме всеки пункт от плана и ще видим какво може да се обърка.

ВАЖНО! Процедурата за обновление на MySQL клъстера на базата на Galera има свои тънкости, които не са описани в статията. Не е удачно да използвате това ръководство в такъв случай.

Част 1: Проверка на конфигурациите

В 8-ата версия на MySQL премахнаха query_cache. Всъщност той бе обявен за остарял още в версия 5.7, но сега е изцяло премахнат. Съответно, необходимо е да се премахнат свързаните директиви. А за кеширането на запитвания сега могат да се използват външни инструменти — например, ProxySQL.

Също така в конфигурацията се откриха остарели директиви относно innodb_file_format. Ако в MySQL 5.7 имаше възможност за избор на формат InnoDB, то 8-ата версия вече работи само с формата Barracuda.

Нашият резултат — премахването на следните директиви:

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

За проверка ще използваме Docker образа на Percona Server. Конфигурацията на сървъра ще поместим в директорията mysql_config_test, а до нея ще създадем директории за данни и логове. Пример за тест на конфигурацията на 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-centos

В резултат на това или в Docker логовете, или в директорията с логове — в зависимост от вашите конфигурации — ще се появи файл, в който са описани проблемните директиви.

Ето какво беше при нас:

2020-04-03T12:44:19.670831Z 0 [Warning] [MY-011068] [Server] Синтаксисът 'expire-logs-days' е остарял и ще бъде премахнат в бъдеща версия. Моля, използвайте binlog_expire_logs_seconds вместо него.
2020-04-03T12:44:19.671678Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' в момента е алиас за набор от символи UTF8MB3, но в бъдеща версия ще бъде алиас за UTF8MB4. Моля, обмислете използването на UTF8MB4, за да бъдете недвусмислени.
2020-04-03T12:44:19.671682Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' е сортировка на остарелия набор от символи UTF8MB3. Моля, обмислете използването на UTF8MB4 с подходяща сортировка вместо това.

Следователно, трябваше допълнително да се справим с кодировките и да заменим остарялата директива expire-logs-days.

Част 2: Проверка на работещите инсталации

В документацията за актуализация има 2 утилити за проверка на базата за съвместимост. Използването им помага на администратора да провери съвместимостта на наличната структура на данните.

Нека започнем с класическата утилита mysqlcheck. Достатъчно е просто да я стартирате:

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

Ако проблеми не бъдат открити, утилитата ще приключи с код 0:

Актуализация на MySQL (Percona Server) от 5.7 до 8.0

Освен това, в съвременните версии на MySQL е налична утилитата mysql-shell (в случая на Percona това е пакетът percona-mysql-shell). Тя е заместител на класическия клиент mysql и комбинира функции на клиент, редактор на SQL код и инструменти за администриране на MySQL. За проверка на сървъра преди актуализация можете да изпълните следната команда през нея:

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

И ето какви забележки получихме:

Актуализация на MySQL (Percona Server) от 5.7 до 8.0

В общи линии, нищо критично — само предупреждения относно кодировките. (вж. по-долу)Общият резултат от изпълнението:

Актуализация на MySQL (Percona Server) от 5.7 до 8.0

Решихме, че актуализацията би трябвало да премине без проблеми.

Забележката относно предупрежденията по-горе показва проблеми с кодировките. Фактът е, че UTF-8 в MySQL до неотдавна не беше "истинска" UTF-8,тъй като съхраняваше само 3 байта вместо 4. В MySQL 8 това най-накрая беше решено да бъде поправено:алиасът utf8 скоро ще води към кодировката utf8mb4, а старите колони в таблиците ще станат utf8mb3.В бъдеще кодировката utf8mb3. ще бъде премахната, но не в този релиз. Затова решихме да поправим кодировките вече на работещата инсталация на СУБД след нейното обновление.

Част 3: Актуализиране на сървърите

Какво може да се обърка, когато разполагате с толкова прекрасен план?.. Напълно осъзнавайки, че нюансите винаги се случват, проведохме първия експеримент на dev клъстера MySQL.

Както вече бе споменато, официалната документация разяснява въпроса за обновяването на MySQL сървъри с реплики. Същността е, че първо трябва да се обновят всички реплики (slave), тъй като MySQL 8 може да репликира от главен сървър с версия 5.7. Някои затруднения се състоят в това, че използваме режим master master, когато отдалеченият главен сървър е в режим read-only. Тоест, фактически производственият трафик постъпва в един ЦОД, а вторият е резервен.

Топологията изглежда по следния начин:

Актуализация на MySQL (Percona Server) от 5.7 до 8.0

Обновлението трябва да започне от репликите mysql replica dc 2, mysql master dc 2 и mysql replica dc 1, а да завърши с сървъра mysql master dc 1. За по-голяма надеждност, спряхме виртуалните машини, направихме им снимки и непосредствено преди обновлението спряхме репликацията с команда STOP SLAVE. В останалата част, обновлението изглежда така:

  1. Всяка реплика рестартираме, добавяйки в конфигурационните файлове 3 опции: skip-networking, skip-slave-start, skip-log-bin. Работата е там, че обновлението на базата генерира бинарни логове с обновление на системните таблици. Тези директиви гарантират, че в базата няма да има промяна на данните на приложението, а в бинарните логове няма да попадне информация за обновлението на системните таблици. Това ще ни помогне да избегнем проблеми при възобновяването на репликацията.
  2. Инсталираме пакета percona-server-server. Важно е да се отбележи, че в версия MySQL 8 не трябва да приключим с команда mysqlupgrade след обновлението на сървъра.
  3. След успешен старт, отново рестартираме сървъра — вече без параметрите, които бяха добавени в първата точка.
  4. Убедяваме се, че репликацията работи успешно: проверяваме SHOW SLAVE STATUS и виждаме, че таблиците със счетоводни данни в базата на приложението се обновяват.

Всичко това изглежда достатъчно просто: обновлението в dev премина успешно. Ок, можем спокойно да планираме нощното обновление за production.

Нямаше тъга — prod обновихме

Обаче прехвърлянето на успешния опит от dev в production не мина без изненади.

За щастие, самият процес на обновление започва с репликите, затова, срещайки трудности, спряхме работата и възстановихме репликата от снимка. Разследването на проблемите отложихме за следващото утро. В логовете имаше следните записи:

2020-01-14T21:43:21.500563Z 2 [ERROR] [MY-012069] [InnoDB] таблицата t1 има 19 колони, но InnoDB речникът има 20 колони
2020-01-14T21:43:21.500722Z 2 [ERROR] [MY-010767] [Server] Грешка при коригирането на SE данни за db1.t1
2020-01-14T21:43:24.208365Z 0 [ERROR] [MY-010022] [Server] Неуспешно задействане на DD таблици.
2020-01-14T21:43:24.208658Z 0 [ERROR] [MY-010119] [Server] Прекратяване

Проучването на архивите на различни имейл разпространения в Google доведе до разбирането, че този проблем възниква поради грешка в MySQL. Вероятно, по-скоро става въпрос за грешка в инструментите mysqlcheck и mysqlsh.

Оказва се, че в MySQL е променен начинът на представяне на данните за десетични полета (int, tinyint и т.н.), поради което вътре в mysql-server се използва друг метод за тяхното съхранение. Ако вашата база данни първоначално е била във версия 5.5 или 5.1, а след това сте обновявали до 5.7, може да е необходимо да извършите OPTIMIZE за някои таблици. В такъв случай MySQL ще обнови файловете с данни, превеждайки ги на актуалния формат на съхранение.

Също така, това може да се провери с инструмента 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': 'your_decimal_column',
...

Ако field_type ако е равно на 0, тогава в таблицата се използва стар тип — трябва да се проведе OPTIMIZE. Въпреки това, ако стойността е 246 — вие вече имате нов тип. По-подробно за типовете може да се запознаете в кода.

Освен това, в тази грешка се разглежда втора възможна причина, която ни заобикаля — липсата на InnoDB таблици в системната таблица INNODB_SYS_TABLESPACES, ако те, таблиците, са създадени в версия 5.1. За да избегнете проблеми при актуализация, може да се използва прикаченият SQL скрипт.

Защо не сме имали такива проблеми на dev? Базата там периодично се копира от production — по този начин, таблиците се пресъздават.

За съжаление, в реално функционираща голяма БД не е възможно просто да вземете и изпълните общо OPTIMIZE. Тук помага percona-toolkit: за операция online OPTIMIZE отличен избор е инструментът pt-online-schema-change.

Обновеният план стана такъв:

  1. Да се проведе оптимизация на всички таблици.
  2. Да се проведе актуализация на базите данни.

За да проверим това и да установим времето за актуализация, изключихме един от репликите и за всички таблици стартирахме следната команда:

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

Актуализация на таблиците се извършва без продължителни блокировки, благодарение на факта, че утилитата създава нова временна таблица, в която копира данните от основната таблица. В момента, когато и двете таблици са идентични, оригиналната таблица се блокира и заменя с новата. В нашия случай тестовият старт показа, че за актуализиране на всички таблици ще са необходими около 24 часа, но в същото време копирането на данните предизвикваше прекалено голямо натоварване на дисковете.

За да избегнем това, на продукцията добавихме към командата аргумент --sleep с значение 10 — този параметър регулира дължината на изчакването след прехвърлянето на порция данни в новата таблица. По този начин можем да намалим натоварването, ако реално стартираното приложение е взискателно към времето за отговор.

След успешното извършване на оптимизацията актуализацията премина успешно.

… но не напълно!

Вече след половин час след актуализацията клиентът дойде с проблем. Базата работеше много странно: периодично започваха сброси на връзките. Ето как изглеждаше това в мониторинга:

Актуализация на MySQL (Percona Server) от 5.7 до 8.0

На екрана се вижда зъбчат график, свързан с това, че част от потоките на MySQL-сервера периодично падаха с грешка. В приложението се появиха грешки:

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

Бързият преглед на логовете показа, че демона mysqld не може да получи необходимите ресурси от операционната система. Разглеждайки грешките, открихме в системата «безстопанствени» файлове на политиките 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

Тези файлове са се образували при актуализация на MySQL 5.7 преди няколко години и принадлежат на изтрит пакет. Премахването на файловете и повторното стартиране на услугата apparmor реши проблема:

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

В заключение

Всяка, дори най-простата операция, може да доведе до неочаквани проблеми. И дори наличието на обмислен план не винаги гарантира очаквания резултат. Сега в плановете за актуализация на нашия екип задължително влиза и почистване на излишните файлове, които могат да се появят в резултат на последните действия.

И с това не много професионално графично творчество искам да благодаря на компания Percona за отличните им продукти!

Актуализация на MySQL (Percona Server) от 5.7 до 8.0

P.S.

Прочетете също в нашия блог:

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster