亚马逊AWS官方博客

Amazon Aurora MySQL 版本 2(兼容 MySQL 5.7)升级到版本 3(兼容 MySQL 8.0)检查清单,第 2 部分

第一部分中,我们讨论了从 Amazon Aurora MySQL 兼容版 v2 升级到 v3 时,导致预检查过程失败的最常见问题。在这篇博文中,我们将讨论导致升级时间过长和升级失败的最常见原因。

集群中有处于已准备状态的 XA 事务

Amazon Aurora MySQL 在升级时,如果检测到数据库中有处于已准备状态的 XA 事务,就会取消升级。失效转移或者重新启动数据库不会移除已准备的 XA 事务。在升级之前,您必须搜索已准备的 XA 事务,然后提交或者回滚事务。以下代码是演示操作方法的简短示例。

打开会话并启动 XA 事务,然后关闭会话。

mysql> USE sakila;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed

mysql> XA START 'gtridtest','bqualtest',123456;
Query OK, 0 rows affected (0.00 sec)

mysql> UPDATE actor SET first_name='testname' WHERE actor_id=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> XA END 'gtridtest','bqualtest',123456;
Query OK, 0 rows affected (0.00 sec)

mysql> XA PREPARE 'gtridtest','bqualtest',123456;
Query OK, 0 rows affected (0.00 sec)

mysql> exit;

xid 是 XA 事务标识符。该标识符用于指示语句应用到哪个事务。xid 值由客户端提供或由 MySQL 服务器生成。xid 值包括 1 到 3 个 部分:gtrid [, bqual [, formatID]]gtrid 是全局事务标识符,bqual 是分支限定符,formatID 是标识 gtridbqual 值所用格式的数字。bqualformatID 为可选参数。如果未指定 bqual,则其默认值为 ‘ ‘。如果未指定 formatID,则其默认值为 1。

此时,数据库中有已准备的 XA 事务。使用以下命令来搜索已准备的 XA 事务。

mysql> XA RECOVER CONVERT xid;
+----------+--------------+--------------+----------------------------------------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+----------------------------------------+
| 123456 | 9 | 9 | 0x677472696474657374627175616C74657374 |
+----------+--------------+--------------+----------------------------------------+
1 row in set (0.00 sec)

输出列的含义如下:

  • formatID 是事务 xidformatID 部分
  • gtrid_lengthxidgtrid 部分的长度,以字节为单位
  • bqual_lengthxidbqual 部分的长度,以字节为单位
  • data 是将 xidgtridbqual 部分组合在一起的结果

使用这些值,我们可以提取数据字段的以下部分。

  • gtrid = 0x677472696474657374
  • bqual = 0x627175616C74657374

要回滚,您可以使用 XA ROLLBACK 命令

mysql> XA ROLLBACK 0x677472696474657374,0x627175616C74657374,123456;
Query OK, 0 rows affected (0.01 sec)

集群有大量的表

Aurora MySQL 执行的主要版本升级是一个多阶段过程,如公开文档中所述。 如果集群中有大量的表,预检查和引擎版本升级步骤的持续时间会延长。引擎版本升级过程分为 2 个步骤进行:数据字典升级和服务器升级。

在 MySQL 8.0 和 MySQL 5.7 之间,MySQL 数据字典的存储方式发生了重大变化。在 MySQL 5.7 及更低版本中,MySQL 字典数据存储在数据文件中(.frm 文件、.par 文件、.trn 文件)。例如,如果 innodb_file_per_table =1(这是默认值),则每个 InnoDB 表会具有自己的 .frm 文件。但是,在 MySQL 8.0 中,MySQL 字典数据集中存储在采用 mysql 架构的表中。这带来了一些好处,您可以在 MySQL 文档中了解这些好处。在上述数据字典升级步骤中,服务器使用更新后的定义创建数据字典表,将持久保存的元数据复制到新表,以原子方式用新表替换旧表,并重新初始化数据字典。因此,当集群包含大量表时,升级过程需要将大量元数据文件移除和迁移到表,这会增加升级所用的总时间。Amazon Aurora MySQL 版本升级非常相似,因此,大量表所造成的影响也同样存在。

在服务器升级步骤中,服务器会根据需要处理用户架构中的表。服务器将检查表,并在发现问题时尝试修复表,如果集群中有大量表,尤其是有大型表,这可能会非常耗时

为了减轻在 v2 升级到 v3 期间由于表数量过多造成的影响,我们建议检查并删除不使用的表,例如备份表和旧表分区。升级具有大量表的集群的主要版本时,会占用大量资源,有可能会超过您的日常工作负载。如果您在测试升级期间出现资源争用,请考虑暂时扩展您的生产实例类,并在升级完成后缩减回来。您应该监控关键的 Amazon CloudWatch 指标,包括 CPUUtilization(了解 CPU 争用情况)、FreeableMemorySwapUsage(了解内存压力),以及 NetworkThroughputStorageNetworkThroughput(了解实例吞吐量)。您可以运行以下查询来获取集群中的表数量。

SELECT count(*) AS TOTAL_NUMBER_OF_TABLES FROM INFORMATION_SCHEMA.TABLES;

我们建议在克隆集群中运行它,以尽可能减少对生产环境的影响,因为在具有大量表的生产实例上运行此查询本身就会占用大量资源,再加上活动的生产负载,会导致需要很长时间,并且数据库的性能会降级。

集群有大量的撤消记录

就地升级机制在执行操作时,需要关闭数据库集群。Amazon Aurora MySQL 执行的是干净关闭,这需要完成未完成的操作,例如撤消清除。在执行升级时,即使采用 RDS 蓝绿部署和快照还原方法,如果有大量撤消记录需要清除,也可能会需要大量时间。

在集群的写入器实例上,Amazon Aurora MySQL CloudWatch 指标 RollbackSegmentHistoryListLength(HLL)的值表示数据库为实施多版本并发控制(MVCC,Multi-Version Concurrency Control)而存储的撤消记录数。您也可以运行 SHOW ENIGNE INNODB STATUS,然后在 TRANSACTIONS 部分中查看 History list length 的值。请考虑仅在尽可能缩短历史列表长度后再执行升级。通常,可接受的历史列表长度不超过 10 万条。但是,HLL 速度的下降涉及许多因素,例如应用程序工作负载、架构属性和实例集群配置。如果您需要解决 HLL 过高的问题,请参阅为什么我的 SELECT 查询在我的 Amazon Aurora MySQL 数据库集群上运行缓慢?InnoDB 历史记录列表长度显著增加Purge Configuration。您也可以使用 Amazon RDS 蓝绿部署来解决 HLL 过高的问题。虽然这种方法不会缩短绿色集群的升级时间,但能够尽可能缩短应用程序停机时间。但请注意,由于升级时间延长,绿色集群可能需要更长的时间才能完成同步。

集群有大量正在进行的写入事务(许多行有未提交的更改)

与撤消清除类似,事务回滚发生在干净关闭期间,如果有大量行需要回滚,这可能会导致升级时间延长。请注意,根据服务器的负载,回滚未完成的事务所花费的时间,可能是事务在中断之前处于活动状态的时间的三到四倍。没有什么简单的方法可用于估算回滚时间。您无法取消正在回滚的事务。单纯依靠重新启动数据库或者对集群进行失效转移并不能加快回滚事务的速度,在某些情况下,回滚速度甚至会变慢,因为一些数据需要从磁盘上重新加载到内存中。

因此,在继续升级之前,您应运行以下查询来检查未提交的总行数:

SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX ORDER BY TRX_ROWS_MODIFIED DESC;

表中为每个事务列出一行。TRX_ROWS_MODIFIED 列包含事务修改或插入的行数。请考虑只有在提交或回滚了所有大型事务之后才执行升级。

集群有长时间运行或未提交的空闲事务

长时间运行的只读或读写事务或者未提交的空闲事务可能会使表处于锁定状态,从而导致升级预检查无法完成。因此,升级可能需要很长时间,甚至像卡住一样。出现这种情况时,如果您运行 select * from information_schema.processlist where USER='rdsadmin',则可能会看到 FLUSH LOCAL TABLE 命令处于等待中,状态为 Waiting for table flush,或者 CHECK TABLE 命令处于等待中,状态为 Waiting for table metadata lock。在这种情况下,您可以使用以下查询来找出造成阻塞的事务,并根据可能执行的操作,相应地提交、回滚或终止这些事务。

SELECT * FROM information_schema.innodb_trx\G
SELECT * FROM information_schema.processlist where id=<# trx_mysql_thread_id from innodb_trx table above>;

CALL mysql.rds_kill(#id from processlist table above);

要解决此问题,请在启动升级过程之前确定长时间运行或未提交的空闲事务。为此,您可以运行以下查询:

SELECT a.trx_id,a.trx_state,a.trx_started,
TIMESTAMPDIFF(SECOND, a.trx_started, now()) as "Seconds Transaction Has Been Open",
a.trx_rows_modified,b.id,b.USER,b.host,b.db,b.command,b.time,b.state

from
information_schema.innodb_trx a,information_schema.processlist b

where
a.trx_mysql_thread_id = b.id
order bytrx_started;

然后等待事务完成,或者在可能的情况下终止事务。请注意,如果您终止大型写入事务,则回滚可能需要很长时间,如前一部分所述。

CALL mysql.rds_kill(#id from processlist table above);

您可以使用相同的查询来确定,集群是否正在处理任何数据定义语言(DDL,Data Definition Language)语句。确保在所有 DDL 语句(CREATE、DROP、ALTER、RENAME 和 TRUNCATE)完成后再执行升级,否则 Amazon Aurora MySQL 会取消升级。建议不要在 DDL 运行时中断语句,因为这可能会导致相关表出现数据字典不一致问题。

总结

在这篇博文中,我们讨论了导致升级时间过长和升级失败的最常见原因。随着 Amazon Aurora MySQL 版本 2 将于 2024 年 10 月 31 日终止生命周期,我们建议您尽早将 Aurora MySQL 版本 2 集群升级到 Aurora MySQL v3 的默认次要版本或更高版本,以便利用 Aurora MySQL v3 中提供的新功能和优化。


关于作者

Huy Nguyen 是 AWS Support 的高级工程师。他的专业特长是 Amazon RDS 和 Amazon Aurora。他通过为客户提供指导和技术援助,帮助客户在 AWS 云中构建可扩展、高度可用和安全的解决方案。

Leevon Abuan 是 AWS Support 的数据库工程师。他专注于 Amazon RDS 和 Amazon Aurora 领域,长期帮助客户解决在云端运行数据库时的复杂技术问题。