Буквально 4 дня назад вышла первая стабильная версия Oracle MySQL 8.0.11
Краткий список изменений на русском языке можно прочитать здесь, а полный на английском языке на официальном сайте здесь.
Давайте попробуем обновить Oracle MySQL 5.7.21 до 8.0.11
Исходные данные:
ОС: Oracle Linux Server release 7.1
БД: Oracle MySQL 5.7.21
Задача: Обновиться до версии 8.0.11
Перед тем как обновиться нужно в обязательном порядке посмотреть все используемые настройки из /etc/my.cnf и попытаться понять какие из них в новом релизе 8.0.11 стали неподдерживаемыми (deprecated) и могут помешать запустить наш экземпляр MySQL после обновления, для этого перед обновлением нам стоит прочитать официальную документацию и дополнительно еще эту страницу.
Так же перед обновлением стоит прочитать официальную документацию по стратегии обновления. Ниже я пройдусь по всем пунктам стратегии обновления и поясню их суть.
Так же перед обновлением Вы должны проверить ваши приложения, работающие в БД на предмет совместимости с новой версией.
Например в MySQL 8.0 были добавлены в список зарезервированных некоторые ключевые слова, к примеру слово GROUPS, которые нельзя использовать в запросах без указания кавычек экранирования.
Поэтому я настоятельно рекомендую вначале провести обновление на тестовой среде, проверить работу Ваших приложений с новой версией MySQL и только потом производить обновление на рабочих серверах.
Я провел соответствующие тесты и мои приложения готовы к новой версии MySQL.
Теперь можно приступить к проверка всех БД и выполнения ряда подготовительных действий.
1. Проверка всех БД на соответствие требованиям MySQL 8.0 и конвертация таблиц в InnoDB
Первым делом нужно запустить процедуру проверки всех БД для поиска проблемных участков, это самый первый пункт в стратегии обновления:
# mysqlcheck -u root -p --all-databases --check-upgrade
Результатом должно быть OK по всем БД и таблицам в них.
Далее, мы предполагаем, что у нас экземпляр MySQL без репликации.
Так же у Вас не должно быть секционированных таблиц, в которых используется механизм хранения, который не имеет встроенной поддержки разбиения на разделы. Чтобы идентифицировать такие таблицы, выполните этот запрос:
SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE ENGINE NOT IN ('innodb', 'ndbcluster') AND CREATE_OPTIONS LIKE '%partitioned%';
Любая таблица, указанная в запросе, должна быть изменена для использования движка InnoDB или быть не секционированной. Чтобы изменить механизм хранения таблиц в InnoDB, нужно выполнить запрос вида:
ALTER TABLE table_name ENGINE = INNODB;
Чтобы сделать удалить секционирование у таблицы, выполните запрос вида:
ALTER TABLE table_name REMOVE PARTITIONING;
Вообще выход MySQL 8.0 ознаменовал закат хранилища MyISAM, поэтому оставаться на нем я не вижу смысла и перед обновлением до 8.0 нам нужно конвертировать движок всех таблиц в InnoDB.
Для начала оценим фронт работ с помощью запроса:
SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES as T WHERE T.ENGINE NOT IN ('innodb', 'ndbcluster') AND T.TABLE_SCHEMA NOT IN ('information_schema', 'performance_schema', 'mysql');
Если запрос показал 0 строк, то Вам повезло и у Вас нет ни одной таблицы с движком отличным от InnoDB или NDBCluster.
Если запрос выдал Вам список таблиц, то нужно провести их конвертацию.
Для удобства конвертации составим запросы на конвертацию отдельно для каждой базы, например возьмем БД с именем MYDB:
mysql -u root -p -N -e "SELECT CONCAT('ALTER TABLE ',TABLE_SCHEMA,'.',TABLE_NAME,' ENGINE=InnoDB;') EXEC FROM INFORMATION_SCHEMA.TABLES as T WHERE T.ENGINE='MyISAM' AND T.TABLE_SCHEMA NOT IN ('information_schema', 'performance_schema', 'mysql') AND T.TABLE_SCHEMA = 'MYDB' ORDER BY TABLE_ROWS asc;" > MYDB.sql
У нас получился файл MYDB.sql в котором перечислены команды и все нужные таблицы из БД для конвертации, внешне он выглядит так:
ALTER TABLE MYDB.table_1 ENGINE=InnoDB; ALTER TABLE MYDB.table_2 ENGINE=InnoDB;
Что нужно знать перед конвертацией таблиц:
1. Конвертация может идти долго в зависимости от размера ваших таблиц, в моем запросе самыми последними в списке на конвертацию буду самые большие таблицы;
2. Таблицы с движком InnoDB занимают в 1,5 раза больше места на HDD, так что проверьте есть ли у Вас столько свободного пространства.
3. Прочитайте мою статью «MySQL и ошибка Index column size too large. The maximum column size is 767 bytes.» и выполните соответствующие настройки по избежании появления подобного рода ошибок. Если Вы используете последнюю версию MySQL 5.7.x то с высокой долей вероятности Вас эти ошибки не затронут.
4. Рекомендую конвертировать все ваши БД и таблицы в кодировку utf8mb4, но это не обязательное условие, хотя в MySQL 8.0 кодировкой по умолчанию стала utf8mb4, это нужно знать и учитывать при обновлении.
Теперь нужно остановить все приложения работающие с нашей БД и запустить конвертацию таблиц:
# mysql -u root -p MYDB mysql> source MYDB.sql
В процессе конвертации не должно возникнуть ошибок, но если они появились, то необходимо разобраться с каждой из них отдельно и довести процесс конвертации до конца. В рамках этой статьи я не могу описать все ситуации, поэтому мы будем предполагать, что все прошло успешно.
Двигаемся дальше. Т.к. в MySQL 8.0 был представлен новый механизм хранения системных данных (Transactional Data Dictionary), то перед переходом на MySQL 8.0 мы должны убедиться, что в системной БД mysql нет таблиц с пересекающимися именами из словаря (Data Dictionary), это делается запросом:
SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE LOWER(TABLE_SCHEMA) = 'mysql' and LOWER(TABLE_NAME) IN ( 'catalogs', 'character_sets', 'collations', 'column_statistics', 'column_type_elements', 'columns', 'dd_properties', 'events', 'foreign_key_column_usage', 'foreign_keys', 'index_column_usage', 'index_partitions', 'index_stats', 'indexes', 'parameter_type_elements', 'parameters', 'resource_groups', 'routines', 'schemata', 'st_spatial_reference_systems', 'table_partition_values', 'table_partitions', 'table_stats', 'tables', 'tablespace_files', 'tablespaces', 'triggers', 'view_routine_usage', 'view_table_usage' );
Он должен вернуть 0 строк, тогда все хорошо. В противном случае Вы не сможете обновить свой MySQL до версии 8.0 не устранив эту проблему. Для устранения проблемы нужно переименовать проблемные таблицы с помощью RENAME TABLE.
Следующие требование — длина имени внешнего ключа (foreign key) не должна превышать 64 символа.
Чтобы определить таблицы с слишком длинными именами, выполните запрос:
SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME IN (SELECT LEFT(SUBSTR(ID,INSTR(ID,'/')+1), INSTR(SUBSTR(ID,INSTR(ID,'/')+1),'_ibfk_')-1) FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN WHERE LENGTH(SUBSTR(ID,INSTR(ID,'/')+1))>64);
Все найденные таблицы должны быть приведены в соответствие этого требования. Для этого используйте ALTER TABLE.
И последнее что нужно знать — это то, что обновляемый вами экземпляр MySQL 5.7.x не должен использовать функции которые более не поддерживаются в MySQL 8.0.x:
а) Таблицы, в которых используется механизм хранения, не поддерживаемый в MySQL 8.0, должны быть изменены, чтобы использовать поддерживаемый движок. Например, MySQL 8.0 еще не поддерживает MySQL Cluster, поэтому таблицы NDB должны быть изменены для использования другого механизма хранения.
б) В MySQL 8.0 были удалены некоторые параметры запуска сервера и системные переменные. См. Функции, удаленные в MySQL 8.0 и Раздел 1.5, «Переменные и параметры сервера и состояния, добавленные, устаревшие или удаленные в MySQL 8.0».
Указания на эти разделы я писал в самом начале статьи.
Применительно к моему файлу конфигурации /etc/my.cnf перед обновлениям я удалил следующие настройки:
query_cache_type query_cache_limit query_cache_size
В MySQL 8.0 кэш запросов (query cache) удалили как таковой, так что эти опции и еще несколько более не поддерживаются. Так же более не поддерживаются модификаторы SQL_CACHE и SQL_NO_CACHE в SELECT запросах и статусные переменные Qcache_XXXX.
Так же я удалил настройку log_warnings которая так же не поддерживается, вместо неё используется log_error_verbosity. После обновления я добавлю настройку log_error_verbosity.
Забегая вперед скажу, что так же я закомментировал опцию expire_logs_days, после обновления её нужно заменить на binlog_expire_logs_seconds
Раньше expire_logs_days указывала через какое количество дней бинарный журнал будет удалятся, теперь с помощью binlog_expire_logs_seconds это можно сделать с точностью до секунд.
Так же я использовал плагин validate_password для контроля качества паролей, в версии 8.0 он был заменен отдельным компонентом, поэтому перед обновлением MySQL я закомментировал следующие настройки в /etc/my.cnf:
validate-password=FORCE_PLUS_PERMANENT validate_password_special_char_count=0
У вас могут быть другие опции и настройки, поэтому процедура обновления может быть более сложной.
Теперь можно приступить к обновлению.
2. Добавляем новый репозитарий в Oracle Linux
Посмотрим список включенных репозитариев:
# yum repolist enabled | grep mysql mysql-connectors-community MySQL Connectors Community 49 mysql-tools-community MySQL Tools Community 61 mysql57-community MySQL 5.7 Community Server 255
Добавим новый репозитарий, есть 2 варианта:
Вариант 1 — мы оставляем старые репозитарии для MySQL 5.7 и описываем новый репозитарий в файле /etc/yum.repos.d/mysql-community.repo
# cat <<EOT >> /etc/yum.repos.d/mysql-community.repo [mysql80-community] name=MySQL 8.0 Community Server baseurl=http://repo.mysql.com/yum/mysql-8.0-community/el/7/\$basearch/ enabled=1 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql EOT
Вариант 2 — удаляем пакет со старыми репозитариями для MySQL 5.7 и устанавливаем RPM-пакет, который по сути сделает тоже самое:
# yum remove mysql57-community-release # yum install https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm -y
Я поступил по второму варианту, он более правильный.
Если Вы поступили по Варианту 1, то нужно будет отключить репозитарий версии MySQL 5.7:
# yum-config-manager --disable mysql57-community
Проверим список активных репозитариев:
# yum repolist enabled | grep mysql mysql-connectors-community/x86_64 MySQL Connectors Community 51 mysql-tools-community/x86_64 MySQL Tools Community 63 mysql80-community/x86_64 MySQL 8.0 Community Server 17
Отлично, mysql80-community есть в списке.
Проверим доступные обновления:
# yum makecache fast # yum check-update
В списки на обновление должны присутствовать пакеты:
mysql-community-client.x86_64 8.0.11-1.el7 mysql80-community mysql-community-common.x86_64 8.0.11-1.el7 mysql80-community mysql-community-libs.x86_64 8.0.11-1.el7 mysql80-community mysql-community-libs-compat.x86_64 8.0.11-1.el7 mysql80-community mysql-community-server.x86_64 8.0.11-1.el7 mysql80-community
3. Обновление MySQL
Посмотрим список установленных пакетов:
# yum list installed | grep "^mysql" mysql-community-client.x86_64 5.7.21-1.el7 @mysql57-community mysql-community-common.x86_64 5.7.21-1.el7 @mysql57-community mysql-community-libs.x86_64 5.7.21-1.el7 @mysql57-community mysql-community-libs-compat.x86_64 5.7.21-1.el7 @mysql57-community mysql-community-server.x86_64 5.7.21-1.el6 @mysql57-community mysql80-community-release.noarch
Выясним местоположение лога ошибок mysql:
# cat /etc/my.cnf | egrep '^log-error|^log_error' log_error = /var/log/mysql/error.log
Анализ данного лога очень нам поможет при запуске новой версии MySQL, поэтому в отдельном окне консоли запустим tail:
# tail -f /var/log/mysql/error.log
Теперь выполним обновление пакета mysql-community-server:
# yum update mysql-community-server
Нам предложат обновить ряд пакетов (mysql-community-server, mysql-community-client, mysql-community-common, mysql-community-libs) до версии 8.0.11, соглашаемся. (Будет скачано порядка 370 MB)
Далее по логу мы увидим, что наш MySQL 5.7.21 будет остановлен и запущен уже 8.0.11, но с некоторыми ошибками, которые нам предстоит исправить. Лог я привожу ниже.
..... 2018-04-23T05:34:44.984167Z 0 [Note] /usr/sbin/mysqld: Shutdown complete 2018-04-23T05:34:46.475828Z 0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release. 2018-04-23T05:34:46.481621Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.11) starting as process 4925 2018-04-23T05:34:54.215467Z 0 [Warning] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-001287 - 'validate password plugin' is deprecated and will be removed in a future release. Please use validate_password component instead 2018-04-23T05:35:14.414991Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed. 2018-04-23T05:35:14.474844Z 0 [ERROR] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-001146 - Table 'mysql.component' doesn't exist 2018-04-23T05:35:14.474953Z 0 [Warning] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-003543 - The mysql.component table is missing or has an incorrect definition. 2018-04-23T05:35:14.488186Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.user]. 2018-04-23T05:35:14.488241Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.db]. 2018-04-23T05:35:14.488251Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.tables_priv]. 2018-04-23T05:35:14.488260Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.columns_priv]. 2018-04-23T05:35:14.488268Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.procs_priv]. 2018-04-23T05:35:14.488276Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.proxies_priv]. 2018-04-23T05:35:14.489419Z 0 [ERROR] [MY-013143] [Server] Column count of mysql.user is wrong. Expected 49, found 45. The table is probably corrupted 2018-04-23T05:35:14.489480Z 0 [Warning] [MY-010966] [Server] ACL table mysql.role_edges missing. Some operations may fail. 2018-04-23T05:35:14.489490Z 0 [Warning] [MY-010966] [Server] ACL table mysql.default_roles missing. Some operations may fail. 2018-04-23T05:35:14.489498Z 0 [Warning] [MY-010966] [Server] ACL table mysql.global_grants missing. Some operations may fail. 2018-04-23T05:35:14.489506Z 0 [Warning] [MY-010966] [Server] ACL table mysql.password_history missing. Some operations may fail. 2018-04-23T05:35:14.492335Z 0 [ERROR] [MY-010965] [Server] Missing system table mysql.global_grants; please run mysql_upgrade to create it. 2018-04-23T05:35:14.501952Z 0 [Warning] [MY-010727] [Server] System table 'func' is expected to be transactional. 2018-04-23T05:35:14.524571Z 0 [Warning] [MY-010405] [Repl] Info table is not ready to be used. Table 'mysql.slave_master_info' cannot be opened. 2018-04-23T05:35:14.524641Z 0 [ERROR] [MY-010422] [Repl] Error in checking mysql.slave_master_info repository info type of TABLE. 2018-04-23T05:35:14.524662Z 0 [ERROR] [MY-010415] [Repl] Error creating master info: Error checking repositories. 2018-04-23T05:35:14.524674Z 0 [ERROR] [MY-010426] [Repl] Slave: Failed to initialize the master info structure for channel ''; its record may still be present in 'mysql.slave_master_info' table, consider deleting it. 2018-04-23T05:35:14.524687Z 0 [ERROR] [MY-010529] [Repl] Failed to create or recover replication info repositories. 2018-04-23T05:35:14.528315Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.11' socket: '/var/lib/mysql/mysql.sock' port: 3306 MySQL Community Server - GPL.
Самое важное — это последняя строка, которая говорит нам, что MySQL 8.0.11 был запущен, это очень важно. Если в процессе запуска будут критические ошибки, например в файле конфигурации будут найдены опции которые уже не существуют в новой версии, то MySQL не запустится и выдаст соответствующие ошибки в лог.
Большинство ошибок в логе при первом старте MySQL 8 связан с тем, что мы не обновили системные БД (mysql и sys), давайте сделаем это запустив программу обновления mysql_upgrade:
# mysql_upgrade -u root -p
В процессе обновления должен будет выдан OK по всем базам и таблицам. Если по каким то БД и таблицам будет выдана ошибка обновления, то Вам стоит на них обратить пристальное внимание. В логе error.log в процессе обновления мы увидим ряд предупреждений и возможно даже ошибок — это вполне нормально.
Теперь перезапустим MySQL 8:
# systemctl restart mysqld
Лог ошибок стал значительно меньше, теперь можно устранить те небольшие ошибки, что у нас остались.
4. Дополнительные действия после обновления (исправление ошибок)
Первым предупреждением в логе идет «‘Disabling symbolic links using —skip-symbolic-links (or equivalent) is the default. Consider not using this option as it’ is deprecated and will be removed in a future release.»
Данная опция помечена как deprecated и в будущих релизах будет удалена совсем, поэтому мы должны ее удалить из /etc/my.cnf
Удаляем строку symbolic-links=0 из /etc/my.cnf
Следующее предупреждение «A message intended for a client cannot be sent there as no client-session is attached. Therefore, we’re sending the information to the error-log instead: MY-001287 — ‘validate password plugin’ is deprecated and will be removed in a future release. Please use validate_password component instead»
Оно говорит о том, что плагин validate_password был заменен компонентом и в дальнейшем как плагин будет удален, поэтому мы должны удалить плагин validate_password и активировать новый компонент, выполняем:
Отключим плагин validate_password выполнив команду:
# mysql -u root -p -e "UNINSTALL PLUGIN validate_password;"
Далее взамен плагина validate_password установим его замену в виде компонента:
# mysql -u root -p -e "INSTALL COMPONENT 'file://component_validate_password';" # mysql -u root -p -e "SET GLOBAL validate_password.special_char_count = 0;"
Вместо настройки validate_password_special_char_count в MySQL 8.0 нужно использовать validate_password.special_char_count, выполним замену в фале /etc/mysql.cnf в секции [mysqld]
validate_password.special_char_count = 0
И последний перезапуск MySQL 8:
# systemctl restart mysqld
На этот раз в логе ошибок (см. ниже) лишь 1 незначительное предупреждение связанное с самоподписным SSL сертификатом, его можно игнорировать.
2018-04-23T06:05:48.758044Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.11) MySQL Community Server - GPL. 2018-04-23T06:05:49.347784Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.11) starting as process 5301 2018-04-23T06:05:51.203327Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed. 2018-04-23T06:05:51.333792Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.11' socket: '/var/lib/mysql/mysql.sock' port: 3306 MySQL Community Server - GPL.
У Вас могут быть дополнительные предупреждения если к примеру в /etc/my.cnf прописаны опции: skip-external-locking и skip-name-resolve
На этом обновление MySQL 5.7.21 до версии 8.0.11 можно считать законченным.
До скорых встреч. Если у Вас возникли вопросы или Вы хотите чтобы я помог Вам, то Вы всегда можете связаться со мной разными доступными способами.
Профессионально занимаюсь системным администрированием Linux -серверов и баз данных (MySQL, PostgreSQL) на протяжении последних 24 лет.
Спасибо
Михаил, огромное спасибо! Всё чётко, по полочкам, сэкономили много времени!