
Напредъкът не спира, затова причините да се обновим до актуалните версии на MySQL стават все по-съществени. Съвсем наскоро в един от нашите проекти настъпи моментът за обновяване на удобните клъстери Percona Server 5.7 до версия 8. Всичко това се случва на платформата Ubuntu Linux 16.04. Как да извършим подобна операция с минимално време за престой и с какви проблеми се сблъскахме по време на обновлението — четете в тази статия.
Подготовка
Всяко обновление на сървър за бази данни вероятно е свързано с пренастройка на базата: промени в изискванията за лимити на системни ресурси и корекции на конфигурационните файлове, които трябва да бъдат почистени от остарели директиви.
Преди обновлението задължително ще се обърнем към официалната документация:
- ;
- ;
- ;
- .
И ще съставим план за действие:
- Да коригираме конфигурационните файлове, като премахнем остарелите директиви.
- Да проверим съвместимостта с помощта на инструменти.
- Да обновим slave-базите, като инсталираме пакета
percona-server-server. - Да обновим мастера, като инсталираме същия пакет.
Ще разгледаме всеки пункт от плана и ще видим какво може да се обърка.
ВАЖНО! Процедурата за обновление на MySQL клъстера на базата на Galera има свои тънкости, които не са описани в статията. Не е удачно да използвате това ръководство в такъв случай.
Част 1: Проверка на конфигурациите
В 8-ата версия на MySQL премахнаха query_cache. Всъщност той бе още в версия 5.7, но сега е . Съответно, необходимо е да се премахнат свързаните директиви. А за кеширането на запитвания сега могат да се използват външни инструменти — например, .
Също така в конфигурацията се откриха остарели директиви относно innodb_file_format. Ако в MySQL 5.7 имаше възможност за избор на формат InnoDB, то 8-ата версия вече работи .
Нашият резултат — премахването на следните директиви:
-
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 това е пакетът 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И ето какви забележки получихме:

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

Решихме, че актуализацията би трябвало да премине без проблеми.
Забележката относно предупрежденията по-горе показва проблеми с кодировките. Фактът е, че UTF-8 в MySQL до неотдавна тъй като съхраняваше само 3 байта вместо 4. В MySQL 8 това най-накрая алиасът utf8 скоро ще води към кодировката utf8mb4, а старите колони в таблиците ще станат utf8mb3.В бъдеще кодировката utf8mb3. ще бъде премахната, но не в този релиз. Затова решихме да поправим кодировките вече на работещата инсталация на СУБД след нейното обновление.
Част 3: Актуализиране на сървърите
Какво може да се обърка, когато разполагате с толкова прекрасен план?.. Напълно осъзнавайки, че нюансите винаги се случват, проведохме първия експеримент на dev клъстера MySQL.
Както вече бе споменато, разяснява въпроса за обновяването на MySQL сървъри с реплики. Същността е, че първо трябва да се обновят всички реплики (slave), тъй като MySQL 8 може да репликира от главен сървър с версия 5.7. Някои затруднения се състоят в това, че използваме режим master master, когато отдалеченият главен сървър е в режим read-only. Тоест, фактически производственият трафик постъпва в един ЦОД, а вторият е резервен.
Топологията изглежда по следния начин:

Обновлението трябва да започне от репликите mysql replica dc 2, mysql master dc 2 и mysql replica dc 1, а да завърши с сървъра mysql master dc 1. За по-голяма надеждност, спряхме виртуалните машини, направихме им снимки и непосредствено преди обновлението спряхме репликацията с команда STOP SLAVE. В останалата част, обновлението изглежда така:
- Всяка реплика рестартираме, добавяйки в конфигурационните файлове 3 опции:
skip-networking,skip-slave-start,skip-log-bin. Работата е там, че обновлението на базата генерира бинарни логове с обновление на системните таблици. Тези директиви гарантират, че в базата няма да има промяна на данните на приложението, а в бинарните логове няма да попадне информация за обновлението на системните таблици. Това ще ни помогне да избегнем проблеми при възобновяването на репликацията. - Инсталираме пакета
percona-server-server. Важно е да се отбележи, че в версия MySQL 8 не трябва да приключим с командаmysqlupgradeслед обновлението на сървъра. - След успешен старт, отново рестартираме сървъра — вече без параметрите, които бяха добавени в първата точка.
- Убедяваме се, че репликацията работи успешно: проверяваме
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 доведе до разбирането, че този проблем възниква поради . Вероятно, по-скоро става въпрос за грешка в инструментите 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. За да избегнете проблеми при актуализация, може да се използва .
Защо не сме имали такива проблеми на dev? Базата там периодично се копира от production — по този начин, таблиците се пресъздават.
За съжаление, в реално функционираща голяма БД не е възможно просто да вземете и изпълните общо OPTIMIZE. Тук помага percona-toolkit: за операция online OPTIMIZE отличен избор е инструментът pt-online-schema-change.
Обновеният план стана такъв:
- Да се проведе оптимизация на всички таблици.
- Да се проведе актуализация на базите данни.
За да проверим това и да установим времето за актуализация, изключихме един от репликите и за всички таблици стартирахме следната команда:
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-сервера периодично падаха с грешка. В приложението се появиха грешки:
[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 за отличните им продукти!

P.S.
Прочетете също в нашия блог:
- «»;
- «»;
- «»;
- «»;
- «».
Източник: habr.com
