将 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. 通过安装包更新从数据库 percona-server-server.
  4. 使用相同的包更新 master。

让我们看看计划的每一点,看看哪里可能出问题。

重要! 基于 Galera 更新 MySQL 集群的过程有其自身的微妙之处,本文中未描述。 在这种情况下,您不应使用此指令。

第 1 部分:检查配置

MySQL 在版本 8 中被删除 query_cache。 其实他是 宣布过时 回到版本 5.7,但现在 完全删除。 因此,有必要删除相关指令。 为了缓存请求,您现在可以使用外部工具 - 例如, 代理SQL.

此外,在配置中还有关于过时的指令 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.

为了进行检查,我们将使用 Percona Server 的 Docker 镜像。 我们将服务器配置放在目录中 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] 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.

因此,我们仍然需要找出编码并替换过时的指令 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

我们决定更新应该不会出现问题。

关于上述警告的注释表明编码存在问题。 事实上,MySQL 中的 UTF-8 直到最近才出现 不是“真正的”UTF-8,因为它只存储 3 个字节而不是 4 个。在 MySQL 8 中这终于成为可能 决定修复它: 别名 utf8 很快就会导致编码 utf8mb4,表中的旧列将变为 utf8mb3。 进一步编码 utf8mb3 将被删除,但不会在此版本中删除。 因此,我们决定在更新后更正正在运行的 DBMS 安装上已有的编码。

第 3 部分:服务器更新

当有如此明智的计划时,可能会出现什么问题?……我们充分了解细微差别总是会发生,因此我们在 MySQL 开发集群上进行了第一个实验。

如前所述, 官方文档 涵盖了使用副本更新 MySQL 服务器的问题。 最重要的是,您应该首先更新所有副本(从属),因为 MySQL 8 可以从主版本 5.7 进行复制。 一些困难在于我们使用该模式 大师 <-> 大师,当远程主机处于模式时 唯读。 也就是说,事实上,战斗流量流向一个数据中心,第二个数据中心是备份数据中心。

拓扑如下所示:

将 MySQL(Percona Server)从 5.7 更新到 8.0

更新必须从副本开始 mysql 副本 dc 2, mysql主控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 并看到应用程序数据库中带有计数器的表已更新。

一切看起来都很简单:开发更新成功。 好的,您可以安全地安排每晚生产更新。

没有悲伤 - 我们更新了产品

然而,将成功的开发经验转移到生产中并非没有意外。

幸运的是,更新过程本身是从副本开始的,因此当我们遇到困难时,我们停止工作并从快照恢复副本。 对问题的调查被推迟到第二天早上。 日志包含以下条目:

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

研究了 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': 'you_deciaml_column',
...

如果 field_type 如果它等于 0,则表中使用旧类型 - 您需要执行 OPTIMIZE。 但是,如果该值为 246,则您已经有了一个新类型。 有关类型的更多信息可以在 代码.

而且,在 这个错误 我们正在考虑第二个可能的原因,它绕过了我们:系统表中缺少InnoDB表 INNODB_SYS_TABLESPACES,如果它们、表是在版本 5.1 中创建的。 为了避免更新时出现问题,您可以使用 附上SQL脚本.

为什么我们在开发时没有遇到这样的问题? 数据库定期从生产环境复制 - 因此, 表被重新创建.

不幸的是,在一个真正工作的大型数据库上,您将无法仅获取并执行通用的 OPTIMIZE。 percona-toolkit 将在这里提供帮助:pt-online-schema-change 实用程序非常适合在线 OPTIMIZE 操作。

更新后的计划如下所示:

  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

由于实用程序会创建一个新的临时表,并将数据从主表复制到其中,因此表的更新无需长时间锁定。 当两个表相同时,原始表被锁定并替换为新表。 在我们的例子中,测试运行表明更新所有表大约需要一天的时间,但复制数据会导致磁盘负载过大。

为了避免这种情况,在生产中我们将参数添加到命令中 --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

PS

另请阅读我们的博客:

来源: habr.com

添加评论